[블록체인을 이용한 경력 인증] 전체 거래 조회 추가, 거래 생성 수정

재호·2022년 7월 27일
0

CABB

목록 보기
3/5

인터페이스

< HTTP >

  • 트랜잭션 생성
    URL : /Apply/Career
    Parameter : {http.ResponseWriter w, *http.Request req}
    Receive : “address”, “data”, “applier”, “company”, “career”, “payment”, “job”, “proof” json
    Return : -
    Send : “address” string, “txid” [32]byte
func ApplyCareer(w http.ResponseWriter, req *http.Request) {
}
  • 트랜잭션 전체 조회(By Address)
    URL : /refTx
    Parameter : {http.ResponseWriter w, *http.Request req}
    Receive : “address” : 지갑 주소
    Return : -
    Send : “txID”(배열):트랜잭션 해시, “career”(배열):경력, “company”(배열):회사
func FindAllbyAddr(w http.ResponseWriter, req *http.Request) {
}

특정 월렛 주소의 전체 거래 내역 조회

/cabb/user/httppkg/findAllByAddr.go

package httppkg

import (
	"cabb/user/blockpkg"
	"cabb/user/txpkg"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"net/http"
)

type findReqBody struct {
	Address string `json:"address"`
}

type resBody struct {
	TxID    []string `json:"txID"`
	Career  []string `json:"career"`
	Company []string `json:"company"`
}

//월렛 주소에 해당하는 전체 거래 내역 리스트 조회
func FindAllbyAddr(w http.ResponseWriter, req *http.Request) {
	var body findReqBody

	decoder := json.NewDecoder(req.Body)
	decoder.DisallowUnknownFields()
	err := decoder.Decode(&body)
	//에러 체크
	if err != nil {
		fmt.Print(err)
		return
	}

	//테스트용 더미 데이터
	txs := txpkg.CreateTxDB()
	gb := blockpkg.GenesisBlock()
	bs := blockpkg.NewBlockchain(gb)
	prev := gb.Hash
	height := gb.Height + 1
	address := "address123"
	for j := 0; j < 10; j++ {
		tx := txpkg.NewTx("user_"+fmt.Sprint(j), "company_"+fmt.Sprint(j), fmt.Sprint(j)+"개월", "card", "블록체인 개발자", "proof.png", address)
		txs.AddTx(tx)
		b := blockpkg.NewBlock(prev, height, tx.TxID, "data")
		bs.AddBlock(b)
		prev = b.Hash
		height = b.Height + 1
	}

	list := txs.FindTxByAddr(body.Address, bs)

	res := &resBody{}
	for i := 0; i < len(list); i++ {
		res.TxID = append(res.TxID, hex.EncodeToString((list[i].TxID[:]))) // TxID는 해시값이어서 string()을 사용하면 정상적인 문자열이 나오지 않는다.
		res.Career = append(res.Career, string(list[i].Career))
		res.Company = append(res.Company, string(list[i].Company))
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(res)
}

라우터

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/refTx", httppkg.FindAllbyAddr).Methods("Get")

	http.ListenAndServe(":9000", router)
}

테스트

거래 생성 & 블록 생성 병합

/cabb/user/httppkg/generateTransaction.go

package httppkg

import (
	"bytes"
	"cabb/user/txpkg"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	_ "net/http"
)

// Request 구조체
type Request struct {
	Address string `json:"address"`
	Data    string `json:"data"`
	//T       *txpkg.Tx `json:"transaction"`
	Applier string `json:"applier"`
	Company string `json:"company"`
	Career  string `json:"career"`
	Payment string `json:"payment"`
	Job     string `json:"job"`
	Proof   string `json:"proof"`
}

//Json 타입으로 리턴해주기 위한 구조체
type JsonResponse struct {
	Address string   `json:"address"`
	Txid    [32]byte `json:"txid"`
}

// Generate Transaction
func ApplyCareer(w http.ResponseWriter, req *http.Request) {
	var body Request

	decoder := json.NewDecoder(req.Body)
	decoder.DisallowUnknownFields()
	err := decoder.Decode(&body)
	//에러 체크
	if err != nil {
		fmt.Print(err)
		return
	}

	T := txpkg.NewTx(body.Applier, body.Company, body.Career, body.Payment, body.Job, body.Proof, body.Address)

	Txs := txpkg.CreateTxDB() // [임시] 최초에 만들어서 운용중인 Txs(DB) 가져와야함
	Txid := Txs.AddTx(T)      // Txs(임시)에 트랜잭션 등록
	T.PrintTx()
	fmt.Println("Tx-TxID: ", T.TxID)
	value := map[string]string{
		"txID": hex.EncodeToString(T.TxID[:]),
		"data": body.Data}
	json_data, _ := json.Marshal(value)
	resp, err := http.Post("http://localhost:9000/newBlk", "application/json", bytes.NewBuffer(json_data))
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	// Response 체크.
	respBody, err := ioutil.ReadAll(resp.Body)
	if err == nil {
		str := string(respBody)
		println(str)
	}

	var response = JsonResponse{Address: body.Address, Txid: Txid}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

기존에는 각각의 기능들을 독립적으로 분리해놨었지만, 서비스의 시나리오상 트랜잭션 생성과 블록 생성은 늘 동시에 진행되어야 하기 때문에 코드들은 분리되어 있지만 실제 동작은 한번의 호출로 진행되도록 수정했다.

트랜잭션 생성 코드에 http 호출을 추가해서 트랜잭션 생성 코드 내부에서 블록 생성 요청을 보내도록 수정한 것이다.

/cabb/user/httppkg/generateBlock.go

package httppkg

import (
	"cabb/user/blockpkg"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"net/http"
)

// Response 데이터를 담을 구조체
type blkID struct {
	BlockID [32]byte `json:"BlockID"`
}

// Request 데이터가 담길 구조체
type reqBody struct {
	TxID string `json:"txID"`
	Data string `json:"data"`
}

func CreateNewBlock(w http.ResponseWriter, req *http.Request) {

	//request용 구조체 생성
	var body reqBody

	headerContentTtype := req.Header.Get("Content-Type")
	if headerContentTtype != "application/json" {
		fmt.Println("content type 오류")
		return
	}

	//Json 데이터 파싱
	decoder := json.NewDecoder(req.Body)
	decoder.DisallowUnknownFields()
	err := decoder.Decode(&body)
	//에러 체크
	if err != nil {
		fmt.Print(err)
		return
	}

	prevHash := [32]byte{} // (임시)가장 최근의 블록 해시를 불러와야 함
	height := 0            // (임시)가장 최근 블록의 height 또는 블록체인의 길이를 저장

	// string으로 받은 TxID를 [32]byte로 변환
	var txID [32]byte
	hex.Decode(txID[:], []byte(body.TxID))
	fmt.Println("BLK - txID[32]: ", txID)
	data := body.Data
	fmt.Println(data)

	// response용 구조체 생성
	res := &blkID{}
	// 블록 패키지에 구현해놓은 NewBlock() 실행후 해시값 저장
	b := blockpkg.NewBlock(prevHash, height, txID, data)
	b.PrintBlock()
	res.BlockID = b.Hash
	//Content Type을 JSON으로 설정
	w.Header().Set("Content-Type", "application/json")
	// response 구조체 JSON으로 인코딩후 전송
	json.NewEncoder(w).Encode(res)
}

트랜잭션 생성을 요청할 때 트랜잭션 생성에 필요한 데이터뿐만 아니라 블록 생성에 필요한 데이터까지 함께 받도록 해서 트랜잭션 내부에서 블록 요청을 할 때 데이터 처리도 함께 해주도록 되어있다.

라우터

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/Apply/Career", httppkg.ApplyCareer).Methods("Post")
    router.HandleFunc("/newBlk", httppkg.CreateNewBlock).Methods("Post")
    
	http.ListenAndServe(":9000", router)
}

테스트



실제 response 데이터는 트랜잭션의 address와 id 값 뿐이지만 생성되는 블록에 대해서는 터미널에 출력을 해서 정상적인 output인지 테스트 하였다.

Git

https://github.com/HEOHEOHEOseoul/career/tree/master

profile
Java, Spring, SpringMVC, JPA, MyBatis

0개의 댓글