この記事は、以下に紹介した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);
他にもテストスクリプトに様々なトランザクションを記述しているのでぜひお試しください!