테스트 네트워크 디렉터리로 이동
yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ ^C yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$
초기 상태에서 작동하려고 합니다. 다음 명령은 활성 또는 오래된 도커 컨테이너를 종료하고 이전에 생성된 아티팩트를 제거
yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ ./network.sh down
테스트 네워크 시작(./network.sh up)
createChannel
명령이 하는 일mychannel
두 개의 채널 구성원인 Org1과 Org2Anchor peer set for org 'Org2MSP' on channel 'mychannel' Channel 'mychannel' joined
yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ ./network.sh up createChannel
yujeong@yujeong-VirtualBox:~$ cd go/src yujeong@yujeong-VirtualBox:~/go/src$ cd fabric-samples/test-network yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$
yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ ./monitordocker.sh fabric_test
Starting monitoring on all containers on the network fabric_test Unable to find image 'gliderlabs/logspout:latest' locally latest: Pulling from gliderlabs/logspout 8572bc8fb8a3: Pull complete bd801371a862: Pull complete 58100c398b34: Pull complete Digest: sha256:2d81c026e11ac67f7887029dbfd7d36ee986d946066b45c1dabd966278eb5681 Status: Downloaded newer image for gliderlabs/logspout:latest a6139444d7dc3604282693a4fbd4d64f320e9bb27d02bcc5a10e66a3cc2b05d3
체인코드를 패키징하기 전에 체인코드 종속성을 설치해야 함.
자산 전송(기본) 체인코드의 Go 버전이 포함된 폴더로 이동
yujeong@yujeong-VirtualBox:~/go/src$ cd fabric-samples/asset-transfer-basic/chaincode-go
Go 모듈을 사용하여 체인코드 종속성을 설치
종속성은 파일 asset-transfer-basic/chaincode-go
dp go.mod
에 있음.
go.mod
함보셈 ㅋㅋ
yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/asset-transfer-basic/chaincode-go$ cat go.mod module github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go go 1.17 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a github.com/hyperledger/fabric-contract-api-go v1.2.1 github.com/hyperledger/fabric-protos-go v0.3.0 github.com/stretchr/testify v1.8.2 google.golang.org/protobuf v1.28.1 ) ~머시기
asset-transfer-basic/chaincode-go/chaincode/smartcontract.go
을 열어서 스마트 계약 시작 시 계약 API를 사용하여 SmartContract
유형을 정의하는 방법을 확인 가능
아래 체인코드 작성법에 대 더 궁금하다면 : Writing Your First Chaincode
지금은 테스트 듀토리얼 따라지만 나중에 ㄹㅇ 우리 네트크 생성할 때는 아래 처럼 생성하고 nano로 코드 쓰면 될듯, nano 이후 줄은 체인코드 패키징 전 모듈화 하는건데 난 빈파일에 해서 그런가 안대네 나중에 코드 진짜 짜고 해봄. ㅇㅇ
yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ mkdir atcc && cd atcc mkdir: `atcc' 디렉터리를 만들 수 없습니다: 파일이 있습니다 yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ ls CHAINCODE_AS_A_SERVICE_TUTORIAL.md compose prometheus-grafana README.md configtx scripts addOrg3 log.txt setOrgEnv.sh atcc monitordocker.sh system-genesis-block basic.tar.gz network.sh channel-artifacts organizations yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ cd atcc yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network/atcc$ go mod init atcc go: creating new go.mod: module atcc yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network/atcc$ touch atcc.go yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network/atcc$ ls atcc.go go.mod yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network/atcc$ nano atcc.go yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network/atcc$ go mod tidy yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network/atcc$ go mod vendor go: no dependencies to vendor
test-network에 있는 체인코드 확인하기
yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/asset-transfer-basic$ cat chaincode-go/chaincode/smartcontract.go
package chaincode
import (
"encoding/json"
"fmt"
"log"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// SmartContract는 자산관리에 대한 함수를 제공. 즉 스마트 컨트렉트를 정의하고, 컨트렉트에 필요한 메서드들을 구현
//= world statte와 주고 받는 데이터를 관리하기 위한 컨트렉트
// 블록체인 원장에서 데터를 읽고 쓰는 스마트 컨트렉트 내 정의된 기능
type SmartContract struct {
contractapi.Contract
}
// Asset은 간단한 assset을 구성하는 것에 대한 기본 세부 정보 = 자산(블록) 객체 정의
// 알파벳 순서로 구조 필드를 삽입하여 여러 언어에 걸쳐 결정
// golang은 marshal to json 명령을 유지하지만 자동으로 정렬하진 않는다.
type Asset struct {
ID string `json:"ID"`
Color string `json:"color"`
Size int `json:"size"`
Owner string `json:"owner"`
AppraisedValue int `json:"appraisedValue"`
}
// InitLedger는 기본 자산 집합을 원장에 추가
// contractapi.TransactionContextInterface : 모의 트랜잭션 컨텍트 for 단위 테스트 작성 단순화(ex 호출 추적, test 설정)
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
// 원장에 추가할 asset 배열
assets := []Asset{
{ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300},
{ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400},
{ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500},
{ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600},
{ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700},
{ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800},
}
//= for asset in assets:
for _, asset := range assets {
//asset(블록체인 컨트렉트 객체(블록))을 JSON으로 직렬화
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
// JSON으로 직렬화된 블록을 world state에 넣기. 넣는 과정에 에러가 생겼다면 err
err = ctx.GetStub().PutState(asset.ID, assetJSON)
if err != nil {
return fmt.Errorf("failed to put to world state. %v", err)
}
}
// 원장에 초기 자산을 모두 정상적으로 put 했다면 null return
return nil
}
// CreateAsset은 지정된 세부 정보와 함께 새 자산을 world state로 발행
func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
//id로 검색해서 원래 있으면 error 리턴 다른 error 떠도 error 리턴
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if exists {
return fmt.Errorf("the asset %s already exists", id)
}
// 매개변수로 받은 값을 바탕으로 블록체인 컨트렉트 객체(블록)생성
asset := Asset{
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
}
// 블록체인 컨트렉트 객체(블록) asset을 JSON 형식으로 직렬화 문제있음 error 리턴
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
// world stste에 저장
return ctx.GetStub().PutState(id, assetJSON)
}
// ReadAsset은 주어진 ID로 world state에 저장된 자산을 반환
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {
// world state에서 id에 해당하는 데이터를 가져옴 문제 있음 error
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err)
}
// 가져왔는데 아무것도 없어도 error
if assetJSON == nil {
return nil, fmt.Errorf("the asset %s does not exist", id)
}
// JSON 데이터를 Aseet 구조체로 변환 문제있음 error
var asset Asset
err = json.Unmarshal(assetJSON, &asset)
if err != nil {
return nil, err
}
// Asset 구조체 반환
return &asset, nil
}
// UpdateAsset은 제공된 매개 변수를 사용하여 world state의 기존 자산을 업데이트
func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
// id로 world state에서 자산 찾기 없거나 erorr 나면 erorr 리턴
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("the asset %s does not exist", id)
}
// 원래 asset을 새 asset으로 덮어쓰기
asset := Asset{
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
}
// 업데이트한 asset을 JSON 형식으로 직렬화 error 나면 error
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
//world state에 넣기
return ctx.GetStub().PutState(id, assetJSON)
}
// DeleteAsset는 world stste에서 주어진 asset을 제거
func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {
// world state에서 id로 찾기 없거나 error 나면 error 리턴
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("the asset %s does not exist", id)
}
//world state에서 id로 지우기
return ctx.GetStub().DelState(id)
}
// AssetExists world state에 주어진 id로 찾아 asset이 존재하면 리턴
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
//world state에서 id로 찾기 없으면 false와 erorr 리턴
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return false, fmt.Errorf("failed to read from world state: %v", err)
}
// 있으면 asset과 null로 리턴
return assetJSON != nil, nil
}
// TransferAsset은 world state에서 지정된 ID를 가진 자산의 소유자 필드를 업데이트하고 이전 소유자를 반환
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) {
//world state에서 id로 찾아서 가져오기
asset, err := s.ReadAsset(ctx, id)
if err != nil {
return "", err
}
// 원래 주인저장하고 새로운 주인으로 변경
oldOwner := asset.Owner
asset.Owner = newOwner
//변경된 asset을 JSON 형식으로 직렬화
assetJSON, err := json.Marshal(asset)
if err != nil {
return "", err
}
//world state에 넣기
err = ctx.GetStub().PutState(id, assetJSON)
if err != nil {
return "", err
}
// 원래 주인 반환
return oldOwner, nil
}
// GetAllAssets는 world state의 모든 asset들을 반환
func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {
// startKey 및 endKey에 대해 빈 문자열이 포함된 범위 쿼리를 실행 = 모두 가져오기
// 체인 코드 네임스페이스의 모든 자산에 대한 개방형 쿼리
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
if err != nil {
return nil, err
}
defer resultsIterator.Close()
// 결과를 저장할 빈 Asset 객체 배열인 assets 생성
var assets []*Asset
// resultsIterator을 돌면서 assets에 추가
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
// JSON -> 블록 객체로 assets에 넣기
var asset Asset
err = json.Unmarshal(queryResponse.Value, &asset)
if err != nil {
return nil, err
}
assets = append(assets, &asset)
}
// 모든 asset 블록이 담긴 assets 반환
return assets, nil
}
asset-transfer-basic/chaincode-go
디렉토리에서 스마트 컨트렉트 종속성 설치yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/asset-transfer-basic$ cd chaincode-go yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/asset-transfer-basic/chaincode-go$ GO111MODULE=on go mod vendor github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go/chaincode/mocks imports github.com/hyperledger/fabric-protos-go/peer imports google.golang.org/grpc imports google.golang.org/grpc/internal/transport imports golang.org/x/net/http2 imports io/fs: package io/fs is not in GOROOT (/usr/local/go/src/io/fs)
yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/asset-transfer-basic/chaincode-go$ cd .. yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/asset-transfer-basic$ cd .. yujeong@yujeong-VirtualBox:~/go/src/fabric-samples$ cd test-network
peer
: 필요한 형식으로 체인코드 패키지를 생성하는 CLIyujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ export PATH=${PWD}/../bin:$PATH
yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ export FABRIC_CFG_PATH=$PWD/../config/
yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ peer version ^[[Apeer: Version: v2.5.4 Commit SHA: e1e8e2e Go version: go1.20.6 OS/Arch: linux/amd64 Chaincode: Base Docker Label: org.hyperledger.fabric Docker Namespace: hyperledger
basic.tar.gz.
라고 이름이 지정된 패키지를 생성--lang
플래그 : 체인 코드 언어를 지정하는 데 사용--path
플래그 : 스마트 계약 코드의 위치를 제공--label
플래그 : 설치된 후 체인코드를 식별할 체인코드 레이블을 지정하는 데 사용yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ peer lifecycle chaincode package basic.tar.gz --path ../asset-transfer-basic/chaincode-go/ --lang golang --label basic_1.0 yujeong@yujeong-VirtualBox:~/go/src/fabric-samples/test-network$ ls CHAINCODE_AS_A_SERVICE_TUTORIAL.md compose organizations README.md configtx prometheus-grafana addOrg3 log.txt scripts basic.tar.gz monitordocker.sh setOrgEnv.sh channel-artifacts network.sh system-genesis-block