パブリックとプライベート間のアトミッククロスチェイン交換

第三者の仲介者が入ることなく、異なるブロックチェーン間でトークンの交換をします。

ユースケース

Alice と Bob は 10 alice.tokens を 10 bob.tokens に交換しようとしています。課題は彼らが同じネットワークに存在していないことです: alice:token は Symbol のプライベートチェーン上に、一方で bob:token は Symbol のパブリックチェーン上に存在しています。

非アトミックな解決方法の場合:

  1. Alice が 10 alice:tokens を Bob へ送信する (プライベートチェーン)

  2. Bob はトランザクションを受信する

  3. Bob が 10 bob:tokens を Alice へ送信する (パブリックチェーン)

  4. Alice はトランザクションを受信する

しかし、彼らはそれほどお互いを信頼しあってはいません。お気づきでしょうが、 Bob は 3 を実行しない場合に Alice's のトークンを保持できます。

このガイドでは、さまざまな参加者とネットワーク間でトークンを安全に交換する定義をする方法を示します。

前提条件

  • 入門セクション を完了している

  • スワップに関与するすべての参加者は、各ブロックチェーンで少なくとも 1 つのアカウントを所有している必要があります。

const alicePublicChainAccount = Account.createFromPrivateKey(
  '',
  NetworkType.MAIN_NET,
);
const alicePrivateChainAccount = Account.createFromPrivateKey(
  '',
  NetworkType.MIJIN,
);

const bobPublicChainAccount = Account.createFromPrivateKey(
  '',
  NetworkType.MAIN_NET,
);
const bobPrivateChainAccount = Account.createFromPrivateKey(
  '',
  NetworkType.MIJIN,
);

const privateChainTransactionHttp = new TransactionHttp(
  'http://localhost:3000',
);
const publicChainTransactionHttp = new TransactionHttp('http://localhost:3000');

const publicChainGenerationHash = process.env.NETWORK_GENERATION_HASH as string;
const privateChainGenerationHash = process.env
  .NETWORK_GENERATION_HASH as string;
const alicePublicChainAccount = symbol_sdk_1.Account.createFromPrivateKey(
  '',
  symbol_sdk_1.NetworkType.MAIN_NET,
);
const alicePrivateChainAccount = symbol_sdk_1.Account.createFromPrivateKey(
  '',
  symbol_sdk_1.NetworkType.MIJIN,
);
const bobPublicChainAccount = symbol_sdk_1.Account.createFromPrivateKey(
  '',
  symbol_sdk_1.NetworkType.MAIN_NET,
);
const bobPrivateChainAccount = symbol_sdk_1.Account.createFromPrivateKey(
  '',
  symbol_sdk_1.NetworkType.MIJIN,
);
const privateChainTransactionHttp = new symbol_sdk_1.TransactionHttp(
  'http://localhost:3000',
);
const publicChainTransactionHttp = new symbol_sdk_1.TransactionHttp(
  'http://localhost:3000',
);
const publicChainGenerationHash = process.env.NETWORK_GENERATION_HASH;
const privateChainGenerationHash = process.env.NETWORK_GENERATION_HASH;
  • Alice のアカウントはプライベートチェーン上で最低でも 10 alice.tokens を保有している必要があります。

  • Bob のアカウントはパブリックチェーン上で最低でも 10 bob.tokens を保有している必要があります。

  • 両方のアカウントは手数料を支払うために十分な手数料が必要です。

方法 #01: SDK を使用する

1. Alice generates a random set of bytes called proof. The proof should have a size between 10 and 1000 bytes. Then, applies a SHA3-256 algorithm to it, obtaining the secret.

  1. Alice は得られた proof を 利用可能なアルゴリズム の1つでハッシュ化して secret を生成します。

const random = crypto.randomBytes(20);
const proof = random.toString('hex');
console.log('Proof:', proof);
const hash = sha3_256.create();
const secret = hash.update(random).hex().toUpperCase();
console.log('Secret:', secret);
const random = crypto.randomBytes(20);
const proof = random.toString('hex');
console.log('Proof:', proof);
const hash = js_sha3_1.sha3_256.create();
const secret = hash.update(random).hex().toUpperCase();
console.log('Secret:', secret);
  1. Alice は SecretLockTransaction TX1 を定義します:

TX1 Property

Value

Type

SecretLockTransaction

Mosaic

10 00D3378709746FC4 (alice token)

Recipient

Bob のアドレス (プライベートチェーン)

Algorithm

SHA3-256

Duration

96 h

Secret

SHA3-256(proof)

Network

Private Chain

const tx1 = SecretLockTransaction.create(
  Deadline.create(epochAdjustment),
  new Mosaic(new MosaicId('00D3378709746FC4'), UInt64.fromUint(10)),
  UInt64.fromUint((96 * 3600) / 30), // assuming one block every 30 seconds
  LockHashAlgorithm.Op_Sha3_256,
  secret,
  bobPrivateChainAccount.address,
  NetworkType.MIJIN,
);
const tx1 = symbol_sdk_1.SecretLockTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  new symbol_sdk_1.Mosaic(
    new symbol_sdk_1.MosaicId('00D3378709746FC4'),
    symbol_sdk_1.UInt64.fromUint(10),
  ),
  symbol_sdk_1.UInt64.fromUint((96 * 3600) / 30), // assuming one block every 30 seconds
  symbol_sdk_1.LockHashAlgorithm.Op_Sha3_256,
  secret,
  bobPrivateChainAccount.address,
  symbol_sdk_1.NetworkType.MIJIN,
);

度アナウンスされると、誰かがシークレットにマッチする証明を発見するまで、このトランザクションはロックされたままです。もしセットされた期限よりも前に、誰もアンロックしない場合は、ロックされた資産は Alice へ返還されます。

  1. Alice は TX1 をプライベートネットワークへアナウンスBob とシークレットを共有 します。

注釈

Bob はチェーンからシークレットを取得する必要があります。シークレットの正当性を検証するのは Bob の責任です。

const tx1Signed = alicePrivateChainAccount.sign(
  tx1,
  privateChainGenerationHash,
);
privateChainTransactionHttp.announce(tx1Signed).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
const tx1Signed = alicePrivateChainAccount.sign(
  tx1,
  privateChainGenerationHash,
);
privateChainTransactionHttp.announce(tx1Signed).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
  1. Bob は以下の SecretLockTransaction TX2パブリックネットワーク へアナウンスします

TX2 Property

Value

Type

SecretLockTransaction

Mosaic

10 10293DE77C684F71 (bob token)

Recipient

Alice のアドレス (パブリックチェーン)

Algorithm

SHA3-256

Duration

84 h

Secret

SHA3-256(proof)

Network

Public Chain

const tx2 = SecretLockTransaction.create(
  Deadline.create(epochAdjustment),
  new Mosaic(new MosaicId('10293DE77C684F71'), UInt64.fromUint(10)),
  UInt64.fromUint((84 * 3600) / 30), // assuming one block every 30 seconds
  LockHashAlgorithm.Op_Sha3_256,
  secret,
  alicePublicChainAccount.address,
  NetworkType.MAIN_NET,
  UInt64.fromUint(2000000),
);
const tx2 = symbol_sdk_1.SecretLockTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  new symbol_sdk_1.Mosaic(
    new symbol_sdk_1.MosaicId('10293DE77C684F71'),
    symbol_sdk_1.UInt64.fromUint(10),
  ),
  symbol_sdk_1.UInt64.fromUint((84 * 3600) / 30), // assuming one block every 30 seconds
  symbol_sdk_1.LockHashAlgorithm.Op_Sha3_256,
  secret,
  alicePublicChainAccount.address,
  symbol_sdk_1.NetworkType.MAIN_NET,
  symbol_sdk_1.UInt64.fromUint(2000000),
);

注釈

資産をアンロックできる時間は、TX1 のタイムフレームよりも短くする必要があります。Alice はシークレットを知っていて、Bob はそれを確信しているので、Alice がシークレットを公開した後に、彼にはいくぶんかの時間があるでしょう。

注釈

TX1 が ロールバック しないことを保証するために、Bob は TX2 をアナウンスする前に、 TX1 の少なくとも maxRollBackBlocks 承認まで待つ必要があります。

const tx2Signed = bobPublicChainAccount.sign(tx2, publicChainGenerationHash);
publicChainTransactionHttp.announce(tx2Signed).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
const tx2Signed = bobPublicChainAccount.sign(tx2, publicChainGenerationHash);
publicChainTransactionHttp.announce(tx2Signed).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
  1. Alice は SecretProofTransaction TX3パブリックネットワーク へアナウンスします。このトランザクションは使用している暗号化アルゴリズム、オリジナルの証明とシークレットを定義します。

TX3 Property

Value

Type

SecretProofTransaction

Recipient

Alice のアドレス (パブリックチェーン)

Algorithm

SHA3-256

Secret

SHA3-256(proof)

Proof

proof

Network

Public Chain

注釈

TX2 が ロールバック しないことを保証するために、Bob は TX3 をアナウンスする前に、 TX2 の少なくとも maxRollBackBlocks 承認まで待つ必要があります。

const tx3 = SecretProofTransaction.create(
  Deadline.create(epochAdjustment),
  LockHashAlgorithm.Op_Sha3_256,
  secret,
  alicePublicChainAccount.address,
  proof,
  NetworkType.MAIN_NET,
  UInt64.fromUint(2000000),
);

const tx3Signed = alicePublicChainAccount.sign(tx3, publicChainGenerationHash);
publicChainTransactionHttp.announce(tx3Signed).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
const tx3 = symbol_sdk_1.SecretProofTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  symbol_sdk_1.LockHashAlgorithm.Op_Sha3_256,
  secret,
  alicePublicChainAccount.address,
  proof,
  symbol_sdk_1.NetworkType.MAIN_NET,
  symbol_sdk_1.UInt64.fromUint(2000000),
);
const tx3Signed = alicePublicChainAccount.sign(tx3, publicChainGenerationHash);
publicChainTransactionHttp.announce(tx3Signed).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
  1. TX3 が承認されると proof が明かされます。TX2 トランザクションはアンロック されて Alice はロックされた資産を受け取ります。

  2. Bob は proof を手に入れて SecretProofTransaction TX4プライベートネットワーク へアナウンスし、ロックされた資産を TX1 から受け取ります。

注釈

TX3 が ロールバック しないことを保証するために、Bob は TX4 をアナウンスする前に、 TX3 の少なくとも maxRollBackBlocks 承認まで待つ必要があります。

TX4 Property

Value

Type

SecretProofTransaction

Recipient

Bob のアドレス (プライベートチェーン)

Algorithm

SHA3-256

Secret

SHA3-256(proof)

Proof

proof

Network

Private Chain

const tx4 = SecretProofTransaction.create(
  Deadline.create(epochAdjustment),
  LockHashAlgorithm.Op_Sha3_256,
  secret,
  bobPrivateChainAccount.address,
  proof,
  NetworkType.MIJIN,
);

const tx4Signed = bobPrivateChainAccount.sign(tx4, privateChainGenerationHash);
privateChainTransactionHttp.announce(tx4Signed).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
const tx4 = symbol_sdk_1.SecretProofTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  symbol_sdk_1.LockHashAlgorithm.Op_Sha3_256,
  secret,
  bobPrivateChainAccount.address,
  proof,
  symbol_sdk_1.NetworkType.MIJIN,
);
const tx4Signed = bobPrivateChainAccount.sign(tx4, privateChainGenerationHash);
privateChainTransactionHttp.announce(tx4Signed).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);

このプロセスはアトミックですか?

このプロセスはアトミックですが、デッドラインを迎える前に完了するまで、多くの時間がかかることになります:

  • ✅ Bob は TX2 をアナウンスしたくありません: Alice は 94 時間後に彼の資産の返還を受信します。

  • ✅ Alice は TX3 をアナウンスしません: Bob は 84 時間後に彼の資産の返還を受取ります。Alice は同様に 94 時間後に彼女の資産をアンロックします。

  • ⚠️ Alice は TX3 に署名しアナウンスします: Alice は Bob の資産を受取ります: Bob は TX1 の正当性が TX2 よりも長いため、Bob は TX4 に署名する十分な時間があります。

  • ⚠️ロールバックは歴史を書き換えます: Alice と Bob それぞれのトランザクションの承認を最低でも maxRollBackBlocks を待ちます。