この記事は、以下に紹介したtsunagi-functionsのRust実装版です。
なお、Rust化の実装についてはオープニングライン社にインターンされているヨシザワさんにご協力いただきました
トランザクション構築の内部処理やノードへの通知方法については以下の記事もご参考ください。
Symbolブロックチェーンをよく知らないという方はこちらで速習することができます。
リポジトリ
tsunagi-functions for Rust
関数群の提供のため、sdkという名称は今後functionsに変更予定です。
テスト
テストスクリプトを以下に置いています。実行することができればそのロジックをそのまま実装に利用することができます。
v_0_1_0_3_5.rs
Cargo.toml
[package]
authors = ["XEMBook", "Yoshizawa Shogo <xxxx@gmail.com>"]
description = "This is a bridge until a de facto standard SDK is available."
name = "tsunagi_sdk"
version = "0.1.0"
edition = "2021"
license = "MIT"
readme = "README.md"
keywords = ["Symbol"]
repository = "https://github.com/xembook/tsunagi-sdk"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
json = "0.12.4"
url = "2.3.1"
reqwest = { version = "0.11", features = ["blocking"] }
rustc-serialize = "0.3.24"
hex = "0.4.3"
sha3 = "0.10.6"
ed25519-dalek = "1"
base32 = "0.4.0"
テスト実行
cargo test
実装例
テストスクリプトから転送トランザクションの書き方を紹介します。
転送トランザクション
use tsunagi_sdk::v0_1::*; // tsunagi_sdkの関数群をインポート
use json::object;
fn main() {
// network情報を定義
let network = object!{
version:1,
network:"TESTNET",
generationHash:"7fccd304802016bebbcd342a332f91ff1f3bb5e902988b352697be245f48e836",
currencyMosaicId:0x3A8416DB2D53B6C8u64,
currencyNamespaceId:0xE74B99BA41F4AFEEu64,
currencyDivisibility:6,
epochAdjustment:1637848847,
catjasonBase:"https://xembook.github.io/tsunagi-sdk/catjson/",
wellknownNodes:[
"https://sym-test.opening-line.jp:3001",
"https://sym-test.opening-line.jp:3001",
"https://sym-test.opening-line.jp:3001",
]
};
// 自分の秘密鍵
let private_key: &str = "94ee0f4d7fe388ac4b04a6a6ae2ba969617879b83616e4d25710d688a89d80c7";
// トランザクションを定義
let tx = object!{
type:"TRANSFER",
signer_public_key:"5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
fee:25000u64,
deadline:7200000u64,
recipient_address:generate_address_id("TCO7HLVDQUX6V7C737BCM3VYJ3MKP6REE2EKROA"),
mosaics:[
{mosaic_id: 0x2A09B7F9097934C2u64, amount: 1u64},
{mosaic_id: 0x3A8416DB2D53B6C8u64, amount: 100u64},
],
message:"Hello Tsunagi(Catjson) SDK!",
};
// catjsonの取得
let catjson = load_catjson(&tx, &network);
// トランザクションレイアウトの取得
let layout = load_layout(&tx, &catjson, false);
// トランザクションの事前準備
let mut prepared_tx = prepare_transaction(&tx, &layout, &network);
// レイアウトの解析とトランザクションデータの注入
let parsed_tx = parse_transaction(&mut prepared_tx, &layout, &catjson, &network);
// トランザクションの構築
let built_tx = build_transaction(&parsed_tx);
// 署名
let signature = sign_transaction(&built_tx, private_key, &network);
// トランザクションの更新
let built_tx = update_transaction(&built_tx, "signature", "value", &signature);
//ペイロード出力
let payload = hexlify_transaction(&built_tx.into(), 0);
// payloadを任意の方法でJson形式でSymbolネットワークへ送信してください。
// Send the payload to the Symbol network in Json format in any way you wish.
assert_eq!(payload,
"dc000000000000001e1a289eef4550fe482ff5a073ba9b91bf38e8623e8767eb54eae5fd48dba354f662dce635ad299efb050cbf187c6b52674613d7e81bb58a4a662d2528d491005f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb0000000001985441a86100000000000000dd6d0000000000989df3aea3852feafc5fdfc2266eb84ed8a7fa242688a8b81c00020000000000c2347909f9b7092a0100000000000000c8b6532ddb16843a64000000000000000048656c6c6f205473756e616769284361746a736f6e292053444b21"
);
}
通知
let json_request = format!(r#"{{"payload":"{}"}}"#, payload);
let r = ureq::put("https://sym-test-02.opening-line.jp:3001/transactions")
.set("Content-Type", "application/json")
.send_string(&json_request);
println!("{}", json_request);
println!("{:?}", r);
連署
連署を必要とするトランザクションの場合は、tx1 に加えて以下のような定義と署名の追加が必要になります。
let cosignature1 = object!{
version:0u64,
signer_public_key:"6199BAE3B241DF60418E258D046C22C8C1A5DE2F4F325753554E7FD9C650AFEC",
signature:"",
};
let cosignature2 = object!{
version:0u64,
signer_public_key:"886ADFBD4213576D63EA7E7A4BECE61C6933C27CD2FF36F85155C8FEBFB6EB4E",
signature:"",
};
let agg_tx = object!{
type:"AGGREGATE_COMPLETE",
signer_public_key:"5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
fee:1000000u64,
deadline:get_deadline(&get_network_info()),
transactions:[tx1,tx2,tx3],
cosignatures:[cosignature1,cosignature2]
};
let catjson = load_catjson(&agg_tx,&get_network_info());
let layout = load_layout(&agg_tx,&catjson,false); //isEmbedded false
let mut prepared_tx = prepare_transaction(&agg_tx,&layout,&get_network_info()); //TX事前準備
let parsed_tx = parse_transaction(&mut prepared_tx,&layout,&catjson,&get_network_info()); //TX解析
let mut built_tx = build_transaction(&parsed_tx); //TX構築
let signature = sign_transaction(&built_tx,PRIVATE_KEY,&get_network_info());
built_tx = update_transaction(&built_tx,"signature","value",&signature);
//トランザクションハッシュ作成
let tx_hash = hash_transaction(&agg_tx["signer_public_key"].to_string(),&signature.to_string(),&built_tx,&get_network_info());
//連署
prepared_tx["cosignatures"][0]["signature"] = cosign_transaction(&tx_hash,BOB_PRIVATE_KEY).into();
prepared_tx["cosignatures"][1]["signature"] = cosign_transaction(&tx_hash,CAROL_PRIVATE_KEY).into();
let cosignatures_layout = layout.iter().find(|&lf| lf["name"] == "cosignatures").unwrap().clone();
let parsed_cosignatures = parse_transaction(&mut prepared_tx,&vec![cosignatures_layout],&catjson,&get_network_info()); //構築
built_tx = update_transaction(&built_tx,"cosignatures","layout",&parsed_cosignatures[0]["layout"]);
let payload = hexlify_transaction(&built_tx.into(), 0);
他にもテストスクリプトに様々なトランザクションを記述しているのでぜひお試しください!