티스토리 뷰

반응형

해당 글은 Hyperledger Fabric 페이지의 게시글을 번역 및 정리한 자료입니다.

원본 사이트 : http://hyperledger-fabric.readthedocs.io/en/release/chaincode4ade.html

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

#이제 코드로 채울 소스 파일을 작성해 보겠습니다.
atom 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 {
    // Extract the function and args from the transaction proposal
    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 the result as success payload
    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 returns the value of the specified asset key
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 /opt/gopath/src/github.com/hyperledger/fabric-samples/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 호출로 이동할 수 있습니다.

[Error 발생 시 해결 방법]

ERROR: for orderer  Cannot start service orderer: driver failed programming external connectivity on endpoint orderer (adcab80ec7ffefe686670618e674070d6a35826782a295e7bc5eb328cd35100a): Bind for 0.0.0.0:7050 failed: port is already allocated

위의 오류가 발생할 경우, 실행중인 도커를 모두 삭제하고 다시 실행하면 됩니다.

docker kill $(docker ps -q)
docker rm $(docker ps -aq) -f


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

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

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

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 컨테이너에서 액세스 할 수 있습니다.

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함