LoginSignup
6
2

More than 1 year has passed since last update.

tsunagi-functionsでSymbolブロックチェーンのトランザクションを自由自在に作ろう!(Go編)

Last updated at Posted at 2022-11-03

この記事は、以下に紹介したtsunagi-functionsのGo実装版です。

トランザクション構築の内部処理やノードへの通知方法については以下の記事もご参考ください。

Symbolブロックチェーンをよく知らないという方はこちらで速習することができます。

リポジトリ

tsunagi-functions for Go

関数群の提供のため、sdkという名称は今後functionsに変更予定です。

テスト

テストスクリプトを以下に置いています。実行することができればそのロジックをそのまま実装に利用することができます。

test_0_1.go

mod.go
module hello
go 1.18

require (
	golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
	golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741
	golang.org/x/text v0.3.6
	golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	github.com/stretchr/testify v1.8.0 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
)

テスト実行
go test

実装例

まずは簡単な実装例を紹介します。

転送トランザクション

func getNetworkInfo() map[string]any {
	return map[string]any{
		"version":1,
		"network":"TESTNET",
		"generationHash":"7fccd304802016bebbcd342a332f91ff1f3bb5e902988b352697be245f48e836",
		"epochAdjustment":1637848847,
		"catjasonBase":"https://xembook.github.io/tsunagi-sdk/catjson/",
	}
}

func getDeadline(network map[string]any) int {
	//	now := time.Now()
	now := network["epochAdjustment"].(int)
	deadline := ((now + 7200) - network["epochAdjustment"].(int)) * 1000
	return deadline
}

func getPayload(tx map[string]any,network map[string]any) string {
	catjson := loadCatjson(tx,network)
	layout := loadLayout(tx,catjson,false)
	preparedTx := prepareTransaction(tx,layout,network) //TX事前準備
	parsedTx := parseTransaction(preparedTx,layout,catjson,network)
	builtTx := buildTransaction(parsedTx) 
	signature := signTransaction(builtTx,"94ee0f4d7fe388ac4b04a6a6ae2ba969617879b83616e4d25710d688a89d80c7",network)
	builtTx = updateTransaction(builtTx,"signature","value",signature)
	//	txHash := hashTransaction(tx1["signer_public_key"].(string),signature,builtTx,network);
	payload := hexlifyTransaction(builtTx,0)
	return payload
}

network  := getNetworkInfo()
deadline := getDeadline(network)

tx1 := map[string]any{
	"type" : "TRANSFER",
	"signer_public_key" : "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" : 25000,
	"deadline" : deadline,
	"recipient_address" : generateAddressId("TCO7HLVDQUX6V7C737BCM3VYJ3MKP6REE2EKROA"),
	"mosaics" : []any{
		map[string]any{"mosaic_id" :  0x2A09B7F9097934C2, "amount" : 1},
		map[string]any{"mosaic_id" :  0x3A8416DB2D53B6C8, "amount" : 100},
	},
	"message" : "Hello Tsunagi(Catjson) SDK!",
}

payload := getPayload(tx1,network)


通知

	client := &http.Client{}
	json, _ := json.Marshal(payload)
	req , _ := http.NewRequest(http.MethodPut, "https://sym-test-02.opening-line.jp:3001/transactions", bytes.NewBuffer(json))
	req.Header.Set("Content-Type", "application/json; charset=utf-8")
	resp, _ := client.Do(req)
	fmt.Println(resp.StatusCode)

連署

連署を必要とするトランザクションの場合は、tx1 に加えて以下のような定義と署名の追加が必要になります。


cosignature1 := map[string]any{
	"version":0,
	"signer_public_key":"6199bae3b241df60418e258d046c22c8c1a5de2f4f325753554e7fd9c650afec",
	"signature":"",
}

cosignature2 := map[string]any{
	"version":0,
	"signer_public_key":"886adfbd4213576d63ea7e7a4bece61c6933c27cd2ff36f85155c8febfb6eb4e",
	"signature":"",
}

aggTx := map[string]any{
	"type" : "AGGREGATE_COMPLETE",
	"signer_public_key" : "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" : 1000000,
	"deadline" : deadline,
	"transactions": []any{tx1,tx2,tx3},
	"cosignatures": []any{cosignature1,cosignature2},
}

catjson := loadCatjson(aggTx,network)
layout := loadLayout(aggTx,catjson,false)
preparedTx := prepareTransaction(aggTx,layout,network) //TX事前準備
parsedTx := parseTransaction(preparedTx,layout,catjson,network)
builtTx := buildTransaction(parsedTx) 
signature := signTransaction(builtTx,"94ee0f4d7fe388ac4b04a6a6ae2ba969617879b83616e4d25710d688a89d80c7",network)
builtTx = updateTransaction(builtTx,"signature","value",signature)
txHash := hashTransaction(aggTx["signer_public_key"].(string),signature,builtTx,network);

preparedTx["cosignatures"].([]any)[0].(map[string]any)["signature"] = cosignTransaction(txHash,"fa6373f4f497773c5cc55c103e348b139461d61fd4b45387e69d08a68000e06b")
preparedTx["cosignatures"].([]any)[1].(map[string]any)["signature"] = cosignTransaction(txHash,"1e090b2a266877a9f88a510af2eb0945a63dc69dbce674ccd83272717d4175cf")

idx := slices.IndexFunc(layout, func(item any) bool {return item.(map[string]any)["name"] == "cosignatures"})
if idx >= 0 {
	cosignaturesLayout := layout[idx].(map[string]any)
	parsedCosignatures := parseTransaction(preparedTx,[]any{cosignaturesLayout},catjson,network)
	builtTx = updateTransaction(builtTx,"cosignatures","layout",parsedCosignatures[0].(map[string]any)["layout"])
}
payload := hexlifyTransaction(builtTx,0);

他にもテストスクリプトに様々なトランザクションを記述しているのでぜひお試しください!

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2