본문 바로가기

Hyperledger Fabric/Document

[HYPERLEDGER FABRIC v1.0]3. 튜토리얼(2)

 Chaincode Tutorials ( 체인코드 튜토리얼 )

What is Chaincode? ( 체인코드란? )

Chaincode는 Go로 작성된 프로그램이며, Java와 같은 다른 프로그래밍 언어로 프로그래밍되어 지정된 인터페이스를 구현합니다. 체인 코드는 검증된 피어 프로세스에서 격리 된 보안 Docker 컨테이너에서 실행됩니다. Chaincode는 응용 프로그램에서 제출 한 트랜잭션을 통해 원장 상태를 초기화하고 관리합니다.

체인 코드는 일반적으로 네트워크 구성원이 동의 한 비즈니스 논리를 처리하므로 "smart contract"로 간주 될 수 있습니다. 체인 코드에 의해 생성 된 상태는 해당 체인 코드로만 범위가 지정되며 다른 체인 코드로 직접 액세스 할 수 없습니다. 그러나 동일한 네트워크 내에서 적절한 권한이 주어지면 체인 코드는 다른 체인 코드를 호출하여 해당 상태에 액세스 할 수 있습니다.

Two Personas ( 두개의 관점 )

우리는 체인 코드에 대해 두 가지 관점을 제시합니다. 

1.개발자 용 Chaincode라는 블록 체인 응용 프로그램 / 솔루션을 개발하는 응용 프로그램 개발자의 관점

2.블록 체인 네트워크를 관리하는 블록 체인 네트워크 운영자를 위한 운영자 용 Chaincode이며 Hyperledger Fabric API를 활용할 사람입니다.

체인 코드를 설치, 인스턴스화 및 업그레이드 할 수 있지만 체인 코드 응용 프로그램의 개발에 관여하지는 않을 것입니다.

Chaincode for Developers ( 개발자를 위한 체인 코드 )

What is Chaincode? ( Chaincode 란 무엇입니까? )

Chaincode는 지정된 인터페이스를 구현하는 Go로 작성된 프로그램 입니다. 결국 Java와 같은 다른 프로그래밍 언어도 지원 될 것입니다. 체인 코드는 검증된 피어 프로세스에서 격리 된 보안 Docker 컨테이너에서 실행됩니다. Chaincode는 응용 프로그램에서 제출 한 트랜잭션을 통해 원장 상태를 초기화하고 관리합니다.

체인 코드는 일반적으로 네트워크 구성원이 동의 한 비즈니스 논리를 처리하므로 "smart contract"과 유사합니다. 체인 코드에 의해 생성 된 원장 상태는 해당 체인 코드로만 범위가 지정되며 다른 체인 코드로 직접 액세스 할 수 없습니다. 적합한 허가가 주어지면 체인 코드는 다른 체인 코드를 호출하여 동일한 네트워크 내에서 해당 상태에 액세스 할 수 있습니다.

다음 섹션에서는 응용 프로그램 개발자의 눈을 통해 체인 코드를 살펴 봅니다. 우리는 간단한 chaincode 샘플 애플리케이션을 제시하고 Chaincode Shim API의 각 메소드의 목적을 설명합니다.

Chaincode API ( 체인코드 API )

모든 체인 코드 프로그램은 수신 된 트랜잭션에 대한 응답으로 메소드가 호출되는 Chaincode 인터페이스를 구현해야합니다. 특히, 체인 코드가 응용 프로그램 상태의 초기화를 포함하여 필요한 초기화를 수행 할 수 있도록 체인 코드가 인스턴스화 또는 업그레이드 트랜잭션을 수신 할 때 Init 메서드가 호출됩니다. Invoke 메서드는 트랜잭션 제안을 처리하기 위해 호출 트랜잭션 수신에 대한 응답으로 호출됩니다.

Simple Asset Chaincode ( 단순 자산 체인 코드 )

우리의 어플리케이션은 원장에 자산 (키 - 값 쌍)을 생성하는 기본 샘플 체인 코드입니다.

Choosing a Location for the Code ( 코드 위치 선택 )

Go에서 프로그래밍을하지 않은 경우 Go 프로그래밍 언어가 설치되어 있고 시스템이 올바르게 구성되어 있는지 확인하십시오. 이제, $ GOPATH / src /의 하위 디렉토리로 chaincode 애플리케이션을위한 디렉토리를 생성하고 싶을 것입니다.

일을 단순하게하기 위해 다음 명령을 사용 해보자.

mkdir -p $GOPATH/src/sacc && cd $GOPATH/src/sacc

#이제 코드로 채울 소스 파일을 작성해 보겠습니다.
touch sacc.go

Housekeeping ( 정리 작업 )

먼저 약간의 정리 작업부터 시작하겠습니다. 모든 체인 코드와 마찬가지로, 그것은 특히 Chaincode 인터페이스, Init 및 Invoke 함수를 구현합니다. 자, 체인 코드에 필요한 의존성에 대한 go import 문을 추가해 봅시다. 체인 코드 심 패키지와 피어 protobuf 패키지를 가져옵니다.

package main

import (
    "fmt"

    "github.com/hyperledger/fabric/core/chaincode/shim"
    "github.com/hyperledger/fabric/protos/peer"
)

Initializing the Chaincode ( 체인 코드 초기화하기 )

다음은이 Init함수를 구현합니다.

// 모든 데이터를 초기화하기 위해 체인 코드 인스턴스화 중에 Init이 호출됩니다.
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {

}

[참고] chaincode 업그레이드는이 기능을 호출합니다. 기존 코드를 업그레이드 할 체인 코드를 작성할 때는 Init 함수를 적절하게 수정해야합니다. 특히 "마이그레이션"이 없거나 업그레이드의 일부로 초기화 할 것이없는 경우 빈 "Init"메소드를 제공하십시오.

다음으로, 우리는 ChaincodeStubInterface.GetStringArgs 함수를 사용하여 Init 호출에 대한 인수를 검색하고 유효성을 검사 할 것입니다. 우리의 경우에는 키 - 값 쌍이 필요합니다.

// 초기화를 위해 체인 코드 인스턴스화 중에 Init가 호출됩니다.
// 데이터. chaincode 업그레이드는이 기능을 호출하여 재설정합니다.
// 데이터를 이전하려면 시나리오를 피하십시오.
// 우연히 원장의 데이터를 부주의하게 가져옵니다!
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
  // Get the args from the transaction proposal
  args := stub.GetStringArgs()
  if len(args) != 2 {
    return shim.Error("Incorrect arguments. Expecting a key and a value")
  }
}

다음으로 호출이 유효하다는 것을 확인 했으므로 원장에 초기 상태를 저장합니다. 이를 위해 우리는 인수로 전달 된 키와 값으로 ChaincodeStubInterface.PutState를 호출 할 것 입니다. 모든 것이 잘되었다고 가정하면 피어를 반환합니다. 초기화가 성공했음을 나타내는 응답 객체.

// 초기화를 위해 체인 코드 인스턴스화 중에 Init가 호출됩니다.
// 데이터. chaincode 업그레이드는이 기능을 호출하여 재설정합니다.
// 데이터를 이전하려면 시나리오를 피하십시오.
// 우연히 원장의 데이터를 부주의하게 가져옵니다!
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
// 거래 제안서에서 args 가져 오기
  args := stub.GetStringArgs()
  if len(args) != 2 {
    return shim.Error("Incorrect arguments. Expecting a key and a value")
  }

// stub.PutState ()를 호출하여 여기에 모든 변수 또는 에셋을 설정합니다.

// 원장에 키와 값을 저장합니다.
  err := stub.PutState(args[0], []byte(args[1]))
  if err != nil {
    return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
  }
  return shim.Success(nil)
}

Invoking the Chaincode ( 체인 코드 호출하기 )

먼저 Invoke함수의 서명을 추가합시다.

// 호출은 chaincode에서 트랜잭션 당 호출됩니다. 각 거래는
// Init 함수에 의해 생성 된 자산의 'get'또는 'set'중 하나입니다. 세트'
// 메소드는 새로운 키 - 값 쌍을 지정하여 새 자산을 만들 수 있습니다.

func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {

}

위의 Init 함수에서와 같이, 우리는 ChaincodeStubInterface에서 인수를 추출해야한다. Invoke 함수의 인수는 호출 할 chaincode 응용 프로그램 함수의 이름입니다. 우리의 경우, 우리의 응용 프로그램은 단순히 자산의 가치를 설정하거나 현재 상태를 검색 할 수있는 두 가지 기능, set과 get을 가질 것입니다. 먼저 ChaincodeStubInterface.GetFunctionAndParameters를 호출하여 해당 체인 코드 응용 프로그램 함수에 대한 함수 이름과 매개 변수를 추출합니다.

// 호출은 chaincode에서 트랜잭션 당 호출됩니다. 각 거래는
// Init 함수에 의해 생성 된 자산의 'get'또는 'set'중 하나입니다. 세트
// 메소드는 새로운 키 - 값 쌍을 지정하여 새 자산을 만들 수 있습니다.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
    // Extract the function and args from the transaction proposal
    fn, args := stub.GetFunctionAndParameters()

}

다음으로 함수 이름을 setor get,로 확인하고 해당 chaincode 응용 프로그램 함수를 호출하여 해당 응답을 gRPC protobuf 메시지로 직렬화하는 함수 shim.Success또는 shim.Error함수를 통해 적절한 응답을 반환 합니다.

// 호출은 chaincode에서 트랜잭션 당 호출됩니다. 각 거래는
// Init 함수에 의해 생성 된 자산의 'get'또는 'set'중 하나입니다. 세트
// 메소드는 새로운 키 - 값 쌍을 지정하여 새 자산을 만들 수 있습니다.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
    // 트랜잭션 제안서에서 함수와 arg를 추출합니다.
    fn, args := stub.GetFunctionAndParameters()

    var result string
    var err error
    if fn == "set" {
            result, err = set(stub, args)
    } else {
            result, err = get(stub, args)
    }
    if err != nil {
            return shim.Error(err.Error())
    }

    // 결과 페이로드를 성공 페이로드로 반환합니다.
    return shim.Success([]byte(result))
}

Implementing the Chaincode Application ( Chaincode 응용 프로그램 구현 )

언급 한 바와 같이, 우리의 chaincode 어플리케이션은 Invoke함수 를 통해 호출 할 수있는 두 개의 함수를 구현 합니다. 이제 이러한 기능을 구현해 보겠습니다. 위에서 언급했듯이 원장의 상태에 액세스 하려면 chaincode shim API 의 ChaincodeStubInterface.PutState 및 ChaincodeStubInterface.GetState 함수를 활용하십시오.

// 원장에 자산을 저장합니다 (키와 값 모두). 키가 존재하면,
// 새 값으로 값을 대체합니다.
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
    if len(args) != 2 {
            return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
    }

    err := stub.PutState(args[0], []byte(args[1]))
    if err != nil {
            return "", fmt.Errorf("Failed to set asset: %s", args[0])
    }
    return args[1], nil
}

// Get은 지정된 자산 키의 값을 반환합니다.
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
    if len(args) != 1 {
            return "", fmt.Errorf("Incorrect arguments. Expecting a key")
    }

    value, err := stub.GetState(args[0])
    if err != nil {
            return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
    }
    if value == nil {
            return "", fmt.Errorf("Asset not found: %s", args[0])
    }
    return string(value), nil
}

Pulling it All Together ( 모두 함께 당기기 )

마지막으로 shim.Start 함수를 main호출 할 함수 를 추가해야 합니다. 다음은 전체 체인 코드 프로그램 소스입니다.

package main

import (
    "fmt"

    "github.com/hyperledger/fabric/core/chaincode/shim"
    "github.com/hyperledger/fabric/protos/peer"
)

// SimpleAsset은 간단한 체인 코드를 구현하여 자산을 관리합니다.
type SimpleAsset struct {
}

// 초기화를 위해 체인 코드 인스턴스화 중에 Init가 호출됩니다.
// 데이터. chaincode 업그레이드는이 기능을 호출하여 재설정합니다.
// 데이터를 이전합니다.
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
    // 거래 제안서에서 args 가져 오기
    args := stub.GetStringArgs()
    if len(args) != 2 {
            return shim.Error("Incorrect arguments. Expecting a key and a value")
    }

    // stub.PutState ()를 호출하여 여기에 모든 변수 또는 에셋을 설정합니다.

    // 원장에 키와 값을 저장합니다.
    err := stub.PutState(args[0], []byte(args[1]))
    if err != nil {
            return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
    }
    return shim.Success(nil)
}

// 호출은 chaincode에서 트랜잭션 당 호출됩니다. 각 거래는
// Init 함수에 의해 생성 된 자산의 'get'또는 'set'중 하나입니다. 세트
// 메소드는 새로운 키 - 값 쌍을 지정하여 새 자산을 만들 수 있습니다.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
    // 트랜잭션 제안서에서 함수와 arg를 추출합니다.
    fn, args := stub.GetFunctionAndParameters()

    var result string
    var err error
    if fn == "set" {
            result, err = set(stub, args)
    } else { // fn이 nil이더라도 'get'이라고 가정합니다.

            result, err = get(stub, args)
    }
    if err != nil {
            return shim.Error(err.Error())
    }

    // 결과 페이로드를 성공 페이로드로 반환합니다.
    return shim.Success([]byte(result))
}

// 원장에 자산을 저장합니다 (키와 값 모두). 키가 존재하면,
// 새 값으로 값을 대체합니다.
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
    if len(args) != 2 {
            return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
    }

    err := stub.PutState(args[0], []byte(args[1]))
    if err != nil {
            return "", fmt.Errorf("Failed to set asset: %s", args[0])
    }
    return args[1], nil
}

// Get은 지정된 자산 키의 값을 반환합니다.
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
    if len(args) != 1 {
            return "", fmt.Errorf("Incorrect arguments. Expecting a key")
    }

    value, err := stub.GetState(args[0])
    if err != nil {
            return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
    }
    if value == nil {
            return "", fmt.Errorf("Asset not found: %s", args[0])
    }
    return string(value), nil
}

// main 함수는 인스턴스화하는 동안 컨테이너에서 chaincode를 시작합니다.
func main() {
    if err := shim.Start(new(SimpleAsset)); err != nil {
            fmt.Printf("Error starting SimpleAsset chaincode: %s", err)
    }
}

Building Chaincode ( 체인코드 빌드하기 )

이제 체인 코드를 컴파일 해 봅시다.

go get -u --tags nopkcs11 github.com/hyperledger/fabric/core/chaincode/shim
go build --tags nopkcs11

오류가 없다고 가정하면 다음 단계로 진행하여 체인 코드를 테스트 할 수 있습니다.

Testing Using dev mode ( 테스트 dev 모드 사용 )

일반적으로 체인 코드는 피어에 의해 시작되고 유지 관리됩니다. 그러나 "dev 모드"에서 chaincode는 사용자가 만들고 시작할 수 있습니다. 이 모드는 신속한 코드 / 빌드 / 실행 / 디버그 사이클 턴어라운드를 위해 체인 코드 개발 단계에서 유용합니다.

우리는 샘플 개발 네트워크를 위해 사전 생성 된 발주자 및 채널 산출물을 활용하여 "dev 모드"를 시작합니다. 따라서 사용자는 즉시 체인 코드 컴파일 및 호출 호출 프로세스로 이동할 수 있습니다.


Install Hyperledger Fabric Samples ( Hyperledger 패브릭 샘플 설치 )

아직 수행하지 않았다면, Hyperledger Fabric Samples 를 설치하십시오.  fabric-samples 복제본 의 chaincode-docker-devmode디렉토리로 이동합니다.

cd chaincode-docker-devmode


Download Docker images ( Docker 이미지 다운로드 )

제공된 도커 작성 스크립트에 대해 "dev 모드"를 실행하려면 4 개의 Docker 이미지가 필요합니다. fabric-samplesRepo 복제본 을 설치하고 플랫폼 별 바이너리를 다운로드 하라는 지침을 따르면 필요한 Docker 이미지가 로컬에 설치되어 있어야합니다.

[참고] 수동으로 이미지를 가져 오기로 선택한 경우 latest 이미지로 다시 태그 지정해야합니다.

docker images 명령을 실행하여 로컬 Docker 레지스트리를 표시합니다. 다음과 유사한 내용이 표시됩니다.

docker images
REPOSITORY                     TAG                                  IMAGE ID            CREATED             SIZE
hyperledger/fabric-tools       latest                               e09f38f8928d        4 hours ago         1.32 GB
hyperledger/fabric-tools       x86_64-1.0.0                         e09f38f8928d        4 hours ago         1.32 GB
hyperledger/fabric-orderer     latest                               0df93ba35a25        4 hours ago         179 MB
hyperledger/fabric-orderer     x86_64-1.0.0                         0df93ba35a25        4 hours ago         179 MB
hyperledger/fabric-peer        latest                               533aec3f5a01        4 hours ago         182 MB
hyperledger/fabric-peer        x86_64-1.0.0                         533aec3f5a01        4 hours ago         182 MB
hyperledger/fabric-ccenv       latest                               4b70698a71d3        4 hours ago         1.29 GB
hyperledger/fabric-ccenv       x86_64-1.0.0                         4b70698a71d3        4 hours ago         1.29 GB

[참고] 다운로드 플랫폼 관련 바이너리를 통해 이미지를 검색하면 추가 이미지가 나열됩니다. 그러나 우리는 이 네 가지에만 관심이 있습니다.

이제 세 개의 터미널을 열고 각각의 chaincode-docker-devmode  디렉토리로 이동하십시오.


Terminal 1 - Start the network ( 터미널 1 - 네트워크 시작 )

docker-compose -f docker-compose-simple.yaml up

위는 SingleSampleMSPSolo주문자 프로파일로 네트워크를 시작하고 "dev 모드"에서 피어를 시작합니다. 또한 체인 코드 환경을위한 컨테이너와 체인 코드와 상호 작용하는 CLI의 두 가지 컨테이너를 추가로 출시합니다. create and join 채널에 대한 명령은 CLI 컨테이너에 내장되어 있으므로 즉시 chaincode 호출로 이동할 수 있습니다.


Terminal 2 - Build & start the chaincode ( 터미널 2 - 체인 코드 작성 및 시작 )

docker exec -it chaincode bash

다음을 보아야합니다.

root@d2629980e76b:/opt/gopath/src/chaincode#

자, chaincode 컴파일 :

cd sacc
go build

이제 chaincode를 실행하십시오.

CORE_PEER_ADDRESS=peer:7051 CORE_CHAINCODE_ID_NAME=mycc:0 ./sacc

체인 코드는 피어 및 체인 코드 로그로 시작되어 피어와의 성공적인 등록을 나타냅니다. 이 단계에서 체인 코드는 어떤 채널과도 연결되지 않습니다. 이것은 instantiate명령을 사용하여 후속 단계에서 수행됩니다.


Terminal 3 - Use the chaincode ( 터미널 3 - 체인 코드 사용 )

사용자가 --peer-chaincodedev모드 상태 일지라도 수명주기 시스템 체인 코드가 정상적으로 점검 할 수 있도록 체인 코드를 설치해야합니다. 이 요구 사항은 향후 --peer-chaincodedev모드 에서 제거 될 수 있습니다 .

CLI 컨테이너를 활용하여 이러한 호출을 유도합니다.

docker exec -it cli bash
peer chaincode install -p chaincodedev/chaincode/sacc -n mycc -v 0
peer chaincode instantiate -n mycc -v 0 -c '{"Args":["a","10"]}' -C myc

이제 "a"값을 "20"으로 변경하기 위해 호출을 실행하십시오.

peer chaincode invoke -n mycc -c '{"Args":["set", "a", "20"]}' -C myc

마지막으로 쿼리 a. 우리는 가치를보아야합니다 20.

peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C myc


Testing new chaincode ( 새로운 체인 코드 테스트 )

기본적으로 sacc 만 마운트합니다. 그러나 chaincode 하위 디렉토리에 추가하고 네트워크를 다시 시작하여 다른 체인 코드를 쉽게 테스트 할 수 있습니다. 이 시점에서 그들은 chaincode 컨테이너에서 액세스 할 수 있습니다.


Chaincode for Operators ( 연산자의 체인 코드 )


Chaincode lifecycle ( 체인 코드 수명주기 )

Hyperledger 패브릭 API는 피어, 발주자 및 MSP와 같은 블록 체인 네트워크의 다양한 노드와 상호 작용할 수있게 해주 며, 또한 인계 피어 노드에 체인 코드를 패키징, 설치, 인스턴스화 및 업그레이드 할 수있게합니다. Hyperledger Fabric 언어 별 SDK는 Hypercode Fabric API의 특성을 추상화하여 응용 프로그램 개발을 용이하게하지만 체인 코드의 수명주기를 관리하는 데 사용할 수 있습니다. 또한 Hyperledger Fabric API는이 문서에서 사용할 CLI를 통해 직접 액세스 할 수 있습니다.

우리는 체인 코드의 라이프 사이클 (package,installinstantiate, upgrade)을 관리하기위한 네 가지 명령을 제공합니다. 향후 릴리스에서는 실제로 중지하지 않고 체인 코드를 비활성화하고 다시 활성화하기 위해  stop 과start트랜잭션을 추가하는 것을 고려하고 있습니다. 체인 코드가 성공적으로 설치되고 인스턴스화 된 후에는 체인 코드가 활성화되어 (실행 중) invoke 트랜잭션을 통해 트랜잭션을 처리 할 수 있습니다. 체인 코드는 설치 후 언제든지 업그레이드 할 수 있습니다.


Packaging ( 패키지 )

chaincode 패키지는 다음 세 부분으로 구성됩니다.

  • ChaincodeDeploymentSpec또는 CDS에 의해 정의 된 체인 코드 . CDS는 체인 코드 패키지를 코드 및 이름 및 버전과 같은 기타 속성으로 정의합니다.
  • 구문에서 승인에 사용 된 것과 같은 정책에 의해 설명하고 설명 할 수있는 선택적 인스턴스화 정책 배서 정책 및
  • 체인 코드를 "소유하고있는"엔티티들의 서명 세트.

서명은 다음과 같은 목적으로 사용됩니다.

  • 체인 코드의 소유권을 확립하기 위해,
  • 패키지의 내용을 검증 할 수 있도록
  • 패키지 변조를 탐지 할 수 있습니다.

채널의 체인 코드 인스턴스화 트랜잭션 생성자는 chaincode의 인스턴스화 정책에 대해 유효성이 검사됩니다.

Creating the package ( 패키지 만들기 )

체인 코드를 패키징하는 데는 두 가지 방법이 있습니다. 하나는 체인 코드의 소유자를 여러 명 갖고 싶어하므로 여러 개의 ID로 서명 된 chaincode 패키지가 있어야합니다. 이 작업 과정에서 우리는 초기에 서명 된 체인 코드 패키지 (a SignedCDS)를 생성해야하며, 서명 된 체인 코드 패키지 는 연속적으로 서명을 위해 다른 각 소유자에게 전달됩니다.

더 간단한 워크 플로우는 install 트랜잭션을 _ 행하는 노드의 ID의 서명 만 갖는 SignedCDS를 전개 할 때 사용 됩니다. 먼저 복잡한 사례를 다룰 것입니다. 그러나 아직 여러 소유자를 걱정할 필요가없는 경우 아래 체인 코드 설치 섹션으로 건너 뛸 수 있습니다. 서명 된 chaincode 패키지를 만들려면 다음 명령을 사용하십시오.

peer chaincode package -n mycc -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -v 0 -s -S -i "AND('OrgA.admin')" ccpack.out

- s 옵션은 단순히 원시 CDS를 작성하는 것이 아니라 여러 소유자가 서명 할 수있는 패키지를 작성합니다. -s가 지정된 경우 다른 소유자가 서명해야하는 경우 -S 옵션도 지정해야합니다. 그렇지 않으면, 프로세스는 CDS 이외에 인스턴스화 정책 만 포함하는 SignedCDS를 작성합니다.

- S 옵션은 프로세스가 core.yaml의 localMspid 등록 정보 값으로 식별되는 MSP를 사용하여 패키지에 서명하도록 지시합니다.

- S 옵션은 선택적입니다. 그러나 패키지가 서명없이 만들어지면 signpackage 명령을 사용하여 다른 소유자가 서명 할 수 없습니다.

선택적 -i 옵션은 체인 코드에 대한 인스턴스화 정책을 지정할 수있게합니다. 인스턴스화 정책은 승인 정책과 동일한 형식을 가지며 체인 코드를 인스턴스화 할 수있는 ID를 지정합니다. 위의 예에서 OrgA의 관리자 만이 chaincode를 인스턴스화 할 수 있습니다. 정책이 제공되지 않으면 기본 정책이 사용되며 피어의 MSP의 관리자 ID 만 체인 코드를 인스턴스화 할 수 있습니다.

패키지 서명 ( Package signing )

생성시 서명 된 체인 코드 패키지는 검사 및 서명을 위해 다른 소유자에게 양도 될 수 있습니다. 워크 플로는 체인 코드 패키지의 대역 외 서명을 지원합니다.

ChaincodeDeploymentSpec은 선택적으로 SignedChaincodeDeploymentSpec (또는 SignedCDS)을 작성하기 위해 집단 소유자가 서명 할 수 있습니다. SignedCDS는 3 가지 요소를 포함합니다 :

  1. CDS에는 체인 코드의 소스 코드, 이름 및 버전이 들어 있습니다.
  2. 보증 정책으로 표현 된 체인 코드의 인스턴스 정책.
  3. 배서의 수단으로 정의 된 체인 코드 소유자 목록 .

[참고] 이 인증 정책은 일부 채널에서 체인 코드가 인스턴스화 될 때 적절한 MSP 보안 주체를 제공하기 위해 대역 외로 결정됩니다. 인스턴스화 정책이 지정되지 않은 경우 기본 정책은 채널의 모든 MSP 관리자입니다.

각 소유자는 ChaincodeDeploymentSpec을 해당 소유자의 신원 (예 : 인증서)과 결합하고 결합 된 결과에 서명함으로써 ChaincodeDeploymentSpec을 보증합니다. 체인 코드 소유자는 다음 명령을 사용하여 이전에 작성한 서명 된 패키지에 서명 할 수 있습니다.

peer chaincode signpackage ccpack.out signedccpack.out

여기서 ccpack.out 및 signedccpack.out은 각각 입력 및 출력 패키지입니다. signedccpack.out에는 로컬 MSP를 사용하여 서명 한 패키지에 대한 추가 서명이 들어 있습니다.

Installing chaincode ( 체인 코드 설치 )

설치 트랜잭션은 체인 코드의 소스 코드를 ChaincodeDeploymentSpec (또는 CDS)이라는 규정 된 형식으로 패키징하고 해당 체인 코드를 실행할 피어 노드에 설치합니다.

[참고] 체인 코드를 실행할 채널의  엔드 피어 노드에 체인 코드를 설치해야합니다.

설치 API에 ChaincodeDeploymentSpec이 제공되면 인스턴스화 정책이 기본값으로 설정되고 빈 소유자 목록이 포함됩니다.

[참고] 체인 코드는 네트워크의 다른 구성원으로부터 체인 코드 논리의 기밀성을 보호하기 위해 체인 코드 소유 구성원의 피어 노드를 승인하는 경우에만 설치해야합니다. 체인 코드가없는 멤버는 체인 코드의 트랜잭션을 승인 할 수 없습니다. 즉, 체인 코드를 실행할 수 없습니다. 그러나 그들은 여전히 ​​장부에 대한 트랜잭션을 확인하고 커밋 할 수 있습니다.

체인 코드를 설치하려면 시스템 체인 코드 섹션에 설명 된 LSCC (Life Cycle System Chaincode)에 SignedProposal을 보냅니다. 예를 들어, CLI를 사용하여 Simple Asset Chaincode 섹션에 설명 된 sacc 샘플 체인 코드를 설치하려면 명령이 다음과 같아야 합니다.

peer chaincode install -n asset_mgmt -v 1.0 -p sacc

CLI는 내부적으로 sacc에 대한 SignedChaincodeDeploymentSpec을 생성하고이를 LSCC에서 Install 메소드를 호출하는 로컬 피어로 보냅니다. -p 옵션의 인수는 사용자의 GOPATH의 소스 트리 내에 있어야하는 체인 코드의 경로를 지정합니다 (예 : $ GOPATH / src / sacc. 명령 옵션에 대한 자세한 설명은 CLI 절을 참조하십시오.

피어에 설치하려면 SignedProposal의 서명이 피어의 로컬 MSP 관리자 중 한 명인 것이어야합니다.

Instantiate ( 인스턴스화 )

인스턴스 생성 트랜잭션은 LSCC (Life Cycle System Chaincode)를 호출하여 채널의 체인 코드를 만들고 초기화합니다. 이것은 체인 코드 채널 바인딩 프로세스입니다. 체인 코드는 여러 채널에 바인딩되어 각 채널에서 개별적으로 독립적으로 작동 할 수 있습니다. 즉, 체인 코드를 설치하고 인스턴스화 할 수있는 다른 채널의 수에 관계없이 상태는 트랜잭션이 제출되는 채널과 분리되어 유지됩니다.

인스턴스화 트랜잭션의 작성자 SignedCDS에 포함 chaincode 인스턴스화 정책을 만족해야하며, 상기 채널 생성의 일부로서 구성되어있는 채널에 작가이어야한다. 악의적 인 엔티티가 체인 코드를 배포하거나 구성원을 속여 언 바운드 채널에서 체인 코드를 실행하는 것을 방지하려면 채널 보안에 중요합니다.

예를 들어, chaincode의 인스턴스화 트랜잭션의 작성자가 채널 관리자의 구성원이어야합니다 있도록 기본 인스턴스 정책은, 어떤 채널 MSP 관리자는 것을 기억합니다. 트랜잭션 제안서가 엔도 서에 도착하면 생성자의 서명을 인스턴스화 정책과 비교하여 검증합니다. 이것은 장부에 커밋하기 전에 트랜잭션 유효성 검사 중에 다시 수행됩니다.

또한 인스턴스 생성 트랜잭션은 채널에서 해당 체인 코드에 대한 보증 정책을 설정합니다. 보증 정책은 채널 구성원이 승인 한 거래 결과에 대한 증명 요구 사항을 설명합니다.

예를 들어 CLI를 사용하여 sacc 체인 코드를 인스턴스화하고 john 및 0으로 상태를 초기화하면 명령은 다음과 같이 표시됩니다.

peer chaincode instantiate -n sacc -v 1.0 -c '{"Args":["john","0"]}' -P "OR ('Org1.member','Org2.member')"

[참고] 보증 정책 (CLI는 폴란드어 표기법을 사용함)에 유의하십시오.이 경우 모든 트랜잭션이 sacc로 처리되도록 Org1 또는 Org2의 멤버가 보증해야합니다 . 즉, Org1 또는 Org2는 유효한 트랜잭션이되도록 sacc 에서  를 실행 한 결과에 서명해야 합니다.

성공적으로 인스턴스화 된 후에는 체인 코드가 채널의 활성 상태가되며 ENDORSER_TRANSACTION 유형의 모든 트랜잭션 제안을 처리 할 준비가됩니다 . 트랜잭션은 보증하는 피어에 도착하면서 동시에 처리됩니다.

Upgrade ( 업그레이드 )

체인 코드는 SignedCDS의 일부인 버전을 변경하여 언제든지 업그레이드 할 수 있습니다. 소유자 및 인스턴스 정책과 같은 다른 부분은 선택 사항입니다. 그러나 체인 코드 이름은 동일해야합니다. 그렇지 않으면 완전히 다른 체인 코드로 간주됩니다.

업그레이드하기 전에 체인 코드의 새 버전을 필요한 엔도 서에 설치해야합니다. 업그레이드는 체인 코드의 새 버전을 채널에 바인드하는 인스턴스화 트랜잭션과 유사한 트랜잭션입니다. 체인 코드의 이전 버전에 바인딩 된 다른 채널은 여전히 ​​이전 버전과 함께 실행됩니다. 즉, upgrade트랜잭션은 한 번에 하나의 채널 (트랜잭션이 제출되는 채널)에만 영향을줍니다.

[참고] 체인 코드의 여러 버전이 동시에 활성화 될 수 있으므로 업그레이드 프로세스가 자동으로 이전 버전을 제거하지 않으므로 사용자는 당분간이를 관리해야합니다.

instantiate트랜잭션 과의 미묘한 차이점이 있습니다. upgrade트랜잭션은 새 정책 (지정된 경우)이 아닌 현재 체인 코드 인스턴스화 정책에 대해 검사됩니다. 이것은 현재 인스턴스화 정책에 지정된 기존 구성원 만이 체인 코드를 업그레이드 할 수 있도록하기위한 것입니다.

[참고]업그레이드하는 동안 chaincode Init함수가 호출되어 데이터 관련 업데이트를 수행하거나 다시 초기화하므로 체인 코드를 업그레이드 할 때 상태를 다시 설정하지 않도록주의해야합니다.

Stop and Start ( 중지 및 시작 )

그 주 stop및 start라이프 사이클 거래는 아직 구현되지 않았습니다. 그러나 각 endorsers에서 chaincode 컨테이너와 SignedCDS 패키지를 제거하여 체인 코드를 수동으로 중지 할 수 있습니다. 이것은 인증 노드가 실행중인 각 호스트 또는 가상 시스템에서 체인 코드 컨테이너를 삭제 한 다음 각 인증 피어 노드에서 SignedCDS를 삭제하여 수행됩니다.

[참고] TODO - 피어 노드에서 CDS를 삭제하려면 먼저 피어 노드의 컨테이너에 들어가야합니다. 이를 수행 할 수있는 유틸리티 스크립트를 제공해야합니다.

docker rm -f <container id>
rm /var/hyperledger/production/chaincodes/<ccname>:<ccversion>

Stop은 업그레이드를하기 전에 모든 피어의 채널에서 체인 코드를 중지 할 수있는 제어 된 방식으로 업그레이드를 수행하는 워크 플로에서 유용합니다.

CLI

[참고] 우리는 Hyperledger Fabric 피어 이진을 위해 플랫폼 특정 바이너리를 배포 할 필요성을 평가하고 있습니다. 당분간, 실행중인 도커 컨테이너에서 명령을 간단히 호출 할 수 있습니다.

현재 사용 가능한 CLI 명령을 보려면 실행중인 fabric-peerDocker 컨테이너 에서 다음 명령을 실행하십시오 .

docker run -it hyperledger/fabric-peer bash
# peer chaincode --help

아래 예제와 비슷한 출력을 보여줍니다 :

Usage:
  peer chaincode [command]

Available Commands:
  install     Package the specified chaincode into a deployment spec and save it on the peer's path.
  instantiate Deploy the specified chaincode to the network.
  invoke      Invoke the specified chaincode.
  package     Package the specified chaincode into a deployment spec.
  query       Query using the specified chaincode.
  signpackage Sign the specified chaincode package
  upgrade     Upgrade chaincode.

Flags:
      --cafile string     Path to file containing PEM-encoded trusted certificate(s) for the ordering endpoint
  -C, --chainID string    The chain on which this command should be executed (default "testchainid")
  -c, --ctor string       Constructor message for the chaincode in JSON format (default "{}")
  -E, --escc string       The name of the endorsement system chaincode to be used for this chaincode
  -l, --lang string       Language the chaincode is written in (default "golang")
  -n, --name string       Name of the chaincode
  -o, --orderer string    Ordering service endpoint
  -p, --path string       Path to chaincode
  -P, --policy string     The endorsement policy associated to this chaincode
  -t, --tid string        Name of a custom ID generation algorithm (hashing and decoding) e.g. sha256base64
      --tls               Use TLS when communicating with the orderer endpoint
  -u, --username string   Username for chaincode operations when security is enabled
  -v, --version string    Version of the chaincode specified in install/instantiate/upgrade commands
  -V, --vscc string       The name of the verification system chaincode to be used for this chaincode

Global Flags:
      --logging-level string       Default logging level and overrides, see core.yaml for full syntax
      --test.coverprofile string   Done (default "coverage.cov")

Use "peer chaincode [command] --help" for more information about a command.

스크립트 응용 프로그램에서의 사용을 용이하게하기 위해 peer명령은 명령 실패시 항상 0이 아닌 리턴 코드를 생성합니다.

체인 코드 명령의 예 :

peer chaincode install -n mycc -v 0 -p path/to/my/chaincode/v0
peer chaincode instantiate -n mycc -v 0 -c '{"Args":["a", "b", "c"]} -C mychannel
peer chaincode install -n mycc -v 1 -p path/to/my/chaincode/v1
peer chaincode upgrade -n mycc -v 1 -c '{"Args":["d", "e", "f"]} -C mychannel
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","e"]}'
peer chaincode invoke -o orderer.example.com:7050  --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}'


System chaincode ( 시스템 체인 코드 )

시스템 체인 코드는 일반적인 체인 코드와 같은 격리 된 컨테이너가 아닌 피어 프로세스 내에서 실행된다는 점을 제외하고는 동일한 프로그래밍 모델을 사용합니다. 따라서 시스템 체인 코드는 피어 실행 파일에 내장되어 있으며 위에서 설명한 동일한 수명주기를 따르지 않습니다. 특히 설치 , 인스턴스화 및 업그레이드 가 시스템 체인 코드에 적용되지 않습니다.

시스템 체인 코드의 목적은 피어와 체인 코드 간 gRPC 통신 비용을 단축하고 관리 유연성을 절충하는 것입니다. 예를 들어 시스템 체인 코드는 피어 이진 파일로만 업그레이드 할 수 있습니다. 또한 컴파일 된 고정 매개 변수 세트로 등록해야하며 보증 정책이나 보증 정책 기능이 없습니다.

시스템 체인 코드는 Hyperledger Fabric에서 시스템 통합 자에 의해 적절하게 대체되거나 수정 될 수 있도록 여러 가지 시스템 동작을 구현하는 데 사용됩니다.

시스템 체인 코드의 현재 목록 :

  1. LSCC Lifecycle 시스템 체인 코드는 위에서 설명한 라이프 사이클 요청을 처리합니다.
  2. CSCC 구성 시스템 체인 코드는 피어 측의 채널 구성을 처리합니다.
  3. QSCC Query 시스템 체인 코드는 블록 및 트랜잭션 가져 오기와 같은 원장 쿼리 API를 제공합니다.
  4. ESCC 인증 시스템 체인 코드는 거래 제안 제안서에 서명함으로써 보증을 처리합니다.
  5. VSCC 유효성 검사 시스템 체인 코드는 보증 정책 및 다중 버전 동시성 제어 검사와 같은 트랜잭션 유효성 검사를 처리합니다.

이러한 시스템 체인 코드, 특히 LSCC, ESCC 및 VSCC가 주 트랜잭션 실행 경로에 있으므로 수정 또는 교체 할 때는주의해야합니다. VSCC가 장부에 커밋하기 전에 블록의 유효성을 검사 할 때 채널의 모든 피어가 장부 발산 (비 결정 성)을 피하기 위해 동일한 유효성 검사를 계산하는 것이 중요합니다. 따라서 VSCC가 수정되거나 대체 된 경우 특별한주의가 필요합니다.