Receipt.go

package model

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/your/import/path/Hasher"
	"github.com/your/import/path/Signer"
)

type Receipt struct {
	PreviousBlockhash string                 `json:"previous_blockhash"`
	Beneficiary       string                 `json:"beneficiary"`
	SignedQuery       map[string]interface{} `json:"signed_query"`
	PublicKey         string                 `json:"public_key"`
	Signature         string                 `json:"signature"`

	Hash string `json:"receipt_hash"`
}

func NewReceipt(initializer map[string]interface{}) *Receipt {
	receipt := &Receipt{
		PreviousBlockhash: initializer["previous_blockhash"].(string),
		Beneficiary:       initializer["beneficiary"].(string),
		SignedQuery:       initializer["signed_query"].(map[string]interface{}),
		PublicKey:         initializer["public_key"].(string),
		Signature:         initializer["signature"].(string),
	}

	receipt.Hash = Hasher.Hash(receipt.ReceiptHeader())

	return receipt
}

func (r *Receipt) Obj() map[string]interface{} {
	return map[string]interface{}{
		"previous_blockhash": r.PreviousBlockhash,
		"receipt_hash":       r.Hash,
		"beneficiary":        r.Beneficiary,
		"signed_query":       r.SignedQuery,
		"public_key":         r.PublicKey,
		"signature":          r.Signature,
	}
}

func (r *Receipt) JSON() string {
	obj := r.Obj()
	jsonData, _ := json.Marshal(obj)
	return string(jsonData)
}

func (r *Receipt) ReceiptHeader() map[string]interface{} {
	return map[string]interface{}{
		"previous_blockhash": r.PreviousBlockhash,
		"beneficiary":        r.Beneficiary,
		"signed_query":       r.SignedQuery,
	}
}

func (r *Receipt) Signer() string {
	queryPublicKey, ok := r.SignedQuery["public_key"].(string)
	if !ok {
		return ""
	}

	return Signer.Address(queryPublicKey)
}

func (r *Receipt) Validity() bool {
	if !r.validateSignedQuery() {
		return false
	}

	if !r.validatePublicKey() {
		return false
	}

	if !Signer.SignatureValidity(Hasher.Hash(r.ReceiptHeader()), r.PublicKey, r.Signature) {
		return false
	}

	query, ok := r.SignedQuery["query"].(map[string]interface{})
	if !ok {
		return false
	}

	queryPublicKey, ok := r.SignedQuery["public_key"].(string)
	if !ok {
		return false
	}

	querySignature, ok := r.SignedQuery["signature"].(string)
	if !ok {
		return false
	}

	if !Signer.SignatureValidity(Hasher.Hash(query), queryPublicKey, querySignature) {
		return false
	}

	queryPreviousBlockhash, ok := query["previous_blockhash"].(string)
	if !ok {
		return false
	}

	queryAddress, ok := query["address"].(string)
	if !ok {
		return false
	}

	if Signer.Address(r.PublicKey) != queryAddress {
		return false
	}

	if r.PreviousBlockhash != queryPreviousBlockhash {
		return false
	}

	return true
}

func (r *Receipt) validateSignedQuery() bool {
	if r.SignedQuery == nil {
		return false
	}

	if _, ok := r.SignedQuery["query"].(map[string]interface{}); !ok {
		return false
	}

	if _, ok := r.SignedQuery["public_key"].(string); !ok {
		return false
	}

	if _, ok := r.SignedQuery["signature"].(string); !ok {
		return false
	}

	return true
}

func (r *Receipt) validatePublicKey() bool {
	if r.PublicKey == "" {
		return false
	}

	return true
}

1. 패키지 및 임포트 선언

설명:

  • package model: 이 코드는 model 패키지에 속해 있습니다.

  • import ( ... ): 필요한 패키지들을 임포트합니다.

    • encoding/json: JSON 인코딩 및 디코딩을 위한 Go 표준 라이브러리입니다.

    • fmt: 형식화된 I/O를 위한 Go 표준 라이브러리입니다.

    • strings: 문자열 관련 기능을 위한 Go 표준 라이브러리입니다.

    • github.com/your/import/path/Hasher: 해시 관련 기능을 제공하는 커스텀 라이브러리입니다.

    • github.com/your/import/path/Signer: 서명 관련 기능을 제공하는 커스텀 라이브러리입니다.

2. Receipt 구조체 정의

설명:

  • type Receipt struct { ... }: Receipt라는 이름의 구조체를 정의합니다.

  • PreviousBlockhash: 이전 블록의 해시를 나타내는 문자열입니다.

  • Beneficiary: 수혜자를 나타내는 문자열입니다.

  • SignedQuery: 서명된 쿼리를 나타내는 맵입니다.

  • PublicKey: 공개 키를 나타내는 문자열입니다.

  • Signature: 서명을 나타내는 문자열입니다.

  • Hash: 영수증의 해시를 나타내는 문자열입니다.

3. 초기화 함수

설명:

  • func NewReceipt(initializer map[string]interface{}) *Receipt: NewReceipt 함수는 initializer라는 맵을 입력으로 받아 새로운 Receipt 구조체를 생성하고 그 포인터를 반환합니다.

    • initializerstring 키와 interface{} 값을 가지는 맵입니다.

  • receipt := &Receipt{ ... }: 새로운 Receipt 구조체를 초기화합니다.

    • 각 필드는 initializer 맵에서 해당 값을 가져와 할당합니다.

  • receipt.Hash = Hasher.Hash(receipt.ReceiptHeader()): ReceiptHeader 메서드를 호출하여 헤더 정보를 가져온 후, 이를 해시화하여 Hash 필드에 할당합니다.

  • return receipt: 초기화된 Receipt 구조체 포인터를 반환합니다.

4. 구조체 데이터를 맵으로 변환하는 함수

설명:

  • func (r *Receipt) Obj() map[string]interface{} { ... }: Receipt 구조체에 대한 메서드로, 구조체의 데이터를 map[string]interface{} 형식으로 변환하여 반환합니다.

    • 각 필드를 키-값 쌍으로 변환하여 맵으로 반환합니다.

5. 구조체 데이터를 JSON 형식으로 변환하는 함수

설명:

  • func (r *Receipt) JSON() string { ... }: Receipt 구조체에 대한 메서드로, 구조체의 데이터를 JSON 문자열로 변환하여 반환합니다.

    • obj := r.Obj(): Obj 메서드를 호출하여 구조체 데이터를 맵으로 변환합니다.

    • jsonData, _ := json.Marshal(obj): json.Marshal 함수를 사용하여 이 맵을 JSON 형식으로 변환합니다.

      • jsonData: 변환된 JSON 바이트 슬라이스를 저장합니다.

      • _: 에러를 무시합니다.

    • return string(jsonData): JSON 바이트 슬라이스를 문자열로 변환하여 반환합니다.

6. 영수증 헤더 데이터를 반환하는 함수

설명:

  • func (r *Receipt) ReceiptHeader() map[string]interface{} { ... }: Receipt 구조체에 대한 메서드로, 헤더 데이터를 map[string]interface{} 형식으로 변환하여 반환합니다.

    • previous_blockhash, beneficiary, signed_query 필드를 포함한 맵을 반환합니다.

7. 서명자의 주소를 반환하는 함수

설명:

  • func (r *Receipt) Signer() string { ... }: Receipt 구조체에 대한 메서드로, 서명자의 주소를 반환합니다.

    • queryPublicKey, ok := r.SignedQuery["public_key"].(string): SignedQuery 맵에서 public_key 값을 가져와 queryPublicKey에 저장합니다. 값이 문자열인지 확인합니다.

    • if !ok { return "" }: public_key 값이 문자열이 아니면 빈 문자열을 반환합니다.

    • return Signer.Address(queryPublicKey): Signer.Address 함수를 호출하여 서명자의 주소를 반환합니다.

8. 영수증의 유효성을 검사하는 함수

설명:

  • func (r *Receipt) Validity() bool { ... }: Receipt 구조체에 대한 메서드로, 영수증의 유효성을 검사합니다.

    • if !r.validateSignedQuery() { return false }: validateSignedQuery 메서드를 호출하여 서명된 쿼리가 유효한지 검사합니다. 유효하지 않으면 false를 반환합니다.

    • if !r.validatePublicKey() { return false }: validatePublicKey 메서드를 호출하여 공개 키가 유효한지 검사합니다. 유효하지 않으면 false를 반환합니다.

    • if !Signer.SignatureValidity(Hasher.Hash(r.ReceiptHeader()), r.PublicKey, r.Signature) { return false }: ReceiptHeader를 해시화한 후, SignatureValidity 함수를 호출하여 서명이 유효한지 검사합니다. 유효하지 않으면 false를 반환합니다.

    • query, ok := r.SignedQuery["query"].(map[string]interface{}): SignedQuery 맵에서 query 값을 가져와 query에 저장합니다. 값이 맵인지 확인합니다.

    • if !ok { return false }: query 값이 맵이 아니면 false를 반환합니다.

    • queryPublicKey, ok := r.SignedQuery["public_key"].(string): SignedQuery 맵에서 public_key 값을 가져와 queryPublicKey에 저장합니다. 값이 문자열인지 확인합니다.

    • if !ok { return false }: public_key 값이 문자열이 아니면 false를 반환합니다.

    • querySignature, ok := r.SignedQuery["signature"].(string): SignedQuery 맵에서 signature 값을 가져와 querySignature에 저장합니다. 값이 문자열인지 확인합니다.

    • if !ok { return false }: signature 값이 문자열이 아니면 false를 반환합니다.

    • if !Signer.SignatureValidity(Hasher.Hash(query), queryPublicKey, querySignature) { return false }: query를 해시화한 후, SignatureValidity 함수를 호출하여 서명이 유효한지 검사합니다. 유효하지 않으면 false를 반환합니다.

    • queryPreviousBlockhash, ok := query["previous_blockhash"].(string): query 맵에서 previous_blockhash 값을 가져와 queryPreviousBlockhash에 저장합니다. 값이 문자열인지 확인합니다.

    • if !ok { return false }: previous_blockhash 값이 문자열이 아니면 false를 반환합니다.

    • queryAddress, ok := query["address"].(string): query 맵에서 address 값을 가져와 queryAddress에 저장합니다. 값이 문자열인지 확인합니다.

    • if !ok { return false }: address 값이 문자열이 아니면 false를 반환합니다.

    • if Signer.Address(r.PublicKey) != queryAddress { return false }: r.PublicKey를 이용하여 주소를 계산한 값이 queryAddress와 다르면 false를 반환합니다.

    • if r.PreviousBlockhash != queryPreviousBlockhash { return false }: r.PreviousBlockhash 값이 queryPreviousBlockhash와 다르면 false를 반환합니다.

    • return true: 모든 검사를 통과하면 true를 반환합니다.

9. 서명된 쿼리를 검사하는 함수

설명:

  • func (r *Receipt) validateSignedQuery() bool { ... }: Receipt 구조체에 대한 메서드로, 서명된 쿼리가 유효한지 검사합니다.

    • if r.SignedQuery == nil { return false }: SignedQuerynil이면 false를 반환합니다.

    • if _, ok := r.SignedQuery["query"].(map[string]interface{}); !ok { return false }: SignedQuery 맵에서 query 값이 맵인지 확인합니다. 맵이 아니면 false를 반환합니다.

    • if _, ok := r.SignedQuery["public_key"].(string); !ok { return false }: SignedQuery 맵에서 public_key 값이 문자열인지 확인합니다. 문자열이 아니면 false를 반환합니다.

    • if _, ok := r.SignedQuery["signature"].(string); !ok { return false }: SignedQuery 맵에서 signature 값이 문자열인지 확인합니다. 문자열이 아니면 false를 반환합니다.

    • return true: 모든 검사를 통과하면 true를 반환합니다.

10. 공개 키를 검사하는 함수

설명:

  • func (r *Receipt) validatePublicKey() bool { ... }: Receipt 구조체에 대한 메서드로, 공개 키가 유효한지 검사합니다.

    • if r.PublicKey == "" { return false }: PublicKey 값이 빈 문자열이면 false를 반환합니다.

    • return true: 공개 키가 유효하면 true를 반환합니다.

Last updated