NBitcoin:一次性全部搭建

NBitcoin : Build Them All

原文作者:Nicolas Dorier

原文地址:https://www.codeproject.com/Articles/835098/NBitcoin-Build-Them-All

译者微博:@从流域到海域

译者博客:blog.csdn.net/solo95

NBitcoin:一次全部搭建

以下是这篇论文所用到的代码的链接:

TransactionBuilderSample-Sources.zip - 473.6 KB

NBitcoin on Github

NBitcoin on Nuget

介绍

本文假设您已经知道比特币是如何工作的。

使用比特币来签署和建立交易从概念上讲很容易理解,但在细节上很混乱。每次你想花钱时,你必须通过签署花费的交易来证明它的所有权或部分所有权具体的过程很复杂,你可以在这里预览一下。所以,我的目标是让任何类型的标准事务都易于构建和签署。 TransactionBuilder进一步支持了Open Asset协议(因此您可以在比特币网络中发布和处理资产,而无需黄金融中介)以及Stealth Payment(用于保护您的隐私)。

您可以在本文链接中找到所有作为示例的易于运行控制台应用程序。

内容

1.设计

2.P2PK,P2PKH,多信用卡付款

3.P2SH payment

  • Alice转账给Satoshi
  • 爱丽斯之后鲍勃转账给Satoshi
  • AliceBobNico公司转账给Satoshi

4.隐形付款

  • DarkSatoshi将钱汇给DarkBob和Alice 5.Colored Coins付款

5.Colored coin 付款

  • GoldGuy向Nico和Satoshi发出黄金,SilverGuy向Alice发出白银
  • Nico将黄金币发送给Satoshi。
  • Satoshi和Alice希望将黄黄金兑换成白银和BTC。

6.地狱交易(仅适用于勇士)

  • GoldGuy和SilverGuy同意将Platinium发送给Satoshi。
  • Satoshi希望用Platinium与Alice的白银,Nico的黄黄金,DarkBob的BTC以及AliceBobNico corp的BTC进行交易。 7.结论

(人名保留,因为有语言上的小trick在,Satoshi即比特币之父中本聪;send按用具体意思翻译跟译成转账,有的时候的,有的时候是发出或发送,它们都是送出的意思,译者注)

设计

TransactionBuilder只需要知道以下内容:

1.它使用那种比特币付款

2.它都掌握什么私钥

3.它把这笔钱发送到哪里

对于第一点,现在有多种类型的比特币可用于付款。

对于P2PK,P2PKH和Multi Sig这些比特币,您只需要知道Coin类,也就是该类的Outpoint(id)属性,和它的TxOut属性(发送多少和发送给谁)。

ScriptCoin也是如此,对于P2SH支付,您还需要知道Redeem属性。

StealthCoin也是和Coin同样的方法,但你要知道它关联的BitcoinStealthAddress属性,还有StealthMetadata属性。(交易中有一个特殊的OP_RETURN ,正如我在这里解释的那样)

然后我们有其他类别的比特币:Colored Coins

一个ColoredCoin 的Amount属性是由AssetId标识的资产的黄金额。

所述Bearer是与BTC连接的底层硬币(和dust很像)

IssuanceCoin只能由资产的发行人支付,其目的是发行新资产。 ColoredCoin代表一个附属于Coin的资产(例如黄黄金)。

一旦你得到了你想要花钱费的硬币,你就有了TransactionBuilder及其附带的流畅接口。

你使用AddCoins方法来告知你可以花什么钱。

你使用AddKeys方法来告知你知道什么私钥。

您使用Send方法发送比特币,SendAsset方法发送Colored Coins或IssueAsset方法发行资产。 SetChange方法是应该发送更改的地方,正如我的先前的文章中所解释的。

SendFees方法,向矿工提供一些小费,以便您的交易更快地得到验证。

BuildTransaction方法将根据您的愿望选择硬币,然后可选择签署(可能部分)您的交易。 SetCoinSelector方法允许您自定义选择硬币来覆盖发送的算法。

SignTransaction方法调用TransactionBuilder方法知道的密钥来签署一个事务。

Shuffle方法将洗牌所有你到现在为止所做的事情,所以区块链观察者不能轻易找到更改地址,或者从TxOut排序中猜测其他的信息。

Verify方法将验证交易完全签署并准备发送到网络。

尽管只有很少的方法,你依然可以发现你曾梦想过的所有交易的无尽的表现力和乐趣。

P2PK,P2PKH,多信用卡付款

让我来向你介绍一下AliceBobSatoshiNico的私钥。

BitcoinSecret alice = new BitcoinSecret("KyJTjvFpPF6DDX4fnT56d2eATPfxjdUPXFFUb85psnCdh34iyXRQ");
BitcoinSecret bob = new BitcoinSecret("KysJMPCkFP4SLsEQAED9CzCurJBkeVvAa4jeN1BBtYS7P5LocUBQ");
BitcoinSecret nico = new BitcoinSecret("L2uC8xNjmcfwje6eweucYvFsmKASbMDALy4rCJBAg8wofpH6barj");
BitcoinSecret satoshi = new BitcoinSecret("L1CpAon5d8zroENbkiMbk3dtd3kcbms6QGF5x475KKTMmXVaJXh3");

Alice发送给Satoshi

在接下来的交易中,Alice过去收到两枚硬币(即比特币,下同)。

{
  "hash": "920edde4ef144b8242d9bc82cef7186d552e06b30443aef1888ac6e4eb868ebf",
  "out": [
    {
      "value": "0.45000000",
      "scriptPubKey": "OP_DUP OP_HASH160 d4339bbd21720095c6842af39ae64c39666bf65c OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.80000000",
      "scriptPubKey": "036d1b36a3a779b12f18c637e7c3ecaf0dfa08699eee276b61d169fc3521f391e6 OP_CHECKSIG"
    }
  ]
}

您可以识别出硬币的一个是P2PKH,另一个是P2PK。你需要知道的唯一事情是,即使Alice保留她的私钥,两者都是可以花出去的。

我们需要将交易结果转换为Coin

Transaction aliceFunding = new Transaction()
{
    Outputs =
    {
        new TxOut("0.45", alice.GetAddress()),
        new TxOut("0.8", alice.Key.PubKey)
    }
};
Coin[] aliceCoins = aliceFunding
                        .Outputs
                        .Select((o, i) => new Coin(new OutPoint(aliceFunding.GetHash(), i), o))
                        .ToArray();

现在,Alice希望将1.00 BTC发送给Satoshi,矿工收取0.001 BTC费用。

var txBuilder = new TransactionBuilder();
var tx = txBuilder
    .AddCoins(aliceCoins)
    .AddKeys(alice.Key)
    .Send(satoshi.GetAddress(), "1.00")
    .SendFees("0.001")
    .SetChange(alice.GetAddress())
    .BuildTransaction(true);
Assert(txBuilder.Verify(tx)); //check fully signed

这给了我以下交易

{
  "hash": "e66bb75f274aa0b0d345f6d81a7ec3d8e945bb7bee27c4d12df6116197effe9f",
  "in": [
    {
      "prev_out": {
        "hash": "920edde4ef144b8242d9bc82cef7186d552e06b30443aef1888ac6e4eb868ebf",
        "n": 0
      },
      "scriptSig": "304402205a72ca5732613578ded3e83231d2d06dcf72af31f3a69c03b65b42f98ca2f24c02206abdcfcbe95740c0290af25a7db8b68ef91978de9e8192508aa9d0852ef3b6a601 036d1b36a3a779b12f18c637e7c3ecaf0dfa08699eee276b61d169fc3521f391e6"
    },
    {
      "prev_out": {
        "hash": "920edde4ef144b8242d9bc82cef7186d552e06b30443aef1888ac6e4eb868ebf",
        "n": 1
      },
      "scriptSig": "3044022011186ae03d8caba31f67e66195b4ca1424887465449fc1920759c0f1743fd07702203352e77fbc67da23a1af744bc2741dcf27f75fc90e7f167397f807aa1ac9195601"
    }
  ],
  "out": [
    {
      "value": "0.24900000",
      "scriptPubKey": "OP_DUP OP_HASH160 d4339bbd21720095c6842af39ae64c39666bf65c OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "1.00000000",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    }
  ]
}

从这两个输入来看,你可以看到Alice的两枚硬币花掉了(1.25 BTC)。

您还可以看到0.249被发回给她(找零),1发送给Satoshi,因此这意味着其中有0.001的费用。(签名是确定性的,所以运行源代码会获得相同的结果)

Alice 之后 Bob 转账给 Satoshi

首先,我们为Bob创建一些硬币,就像我为Alice所做的那样。

Transaction bobFunding = new Transaction()
{
    Outputs =
    {
        new TxOut("0.1", bob.GetAddress()),
        new TxOut("1.8", bob.Key.PubKey)
    }
};
Coin[] bobCoins = bobFunding
                        .Outputs
                        .Select((o, i) => new Coin(new OutPoint(bobFunding .GetHash(), i), o))
                        .ToArray();

现在,让我们假设Alice想要发送0.8 BTC,Bob想要发送0.2 BTC到Satoshi。他们想平摊每个0.0005的费用。这给了我们:

txBuilder = new TransactionBuilder();
tx = txBuilder
    .AddCoins(aliceCoins)
    .AddKeys(alice.Key)
    .Send(satoshi.GetAddress(), "0.8")
    .SetChange(alice.GetAddress())
    .SendFees("0.0005")
    .Then()
    .AddCoins(bobCoins)
    .AddKeys(bob.Key)
    .Send(satoshi.GetAddress(), "0.2")
    .SetChange(bob.GetAddress())
    .SendFees("0.0005")
    .BuildTransaction(true);
Assert(txBuilder.Verify(tx)); //check fully signed

注意Then方法,它允许您独立于Bob的部分构建Alice交易的第一个部分:每个部分都有自己的找零和费用。结果如下:

{
  "hash": "80e477b5b22258cee77783d39e2509c5956cd69e141ad387265fe142032209db",
  "in": [
    {
      "prev_out": {
        "hash": "920edde4ef144b8242d9bc82cef7186d552e06b30443aef1888ac6e4eb868ebf",
        "n": 0
      },
      "scriptSig": "3045022100b3176e8c1164f95e99b6efdb51785662858f30aed6464b25302aa8202654854d02205d765b07b3261d600762ab71d5f527e6dad075ff40dd5f74089687ed2489bb8f01 036d1b36a3a779b12f18c637e7c3ecaf0dfa08699eee276b61d169fc3521f391e6"
    },
    {
      "prev_out": {
        "hash": "920edde4ef144b8242d9bc82cef7186d552e06b30443aef1888ac6e4eb868ebf",
        "n": 1
      },
      "scriptSig": "3044022003925cc41117dc8a690821cd98c3941fe54756ac9b8b558f017725457a9e9650022078f1eba5aeac6d656b4cce6f13f8f56815568eed66c6ea00597d0c1f42ed222a01"
    },
    {
      "prev_out": {
        "hash": "bb82e395bcbee95c7180929f879459e5997b768ea353f6e2528008819668cf5b",
        "n": 1
      },
      "scriptSig": "3045022100cd49a8d8d1383a53a0c43eb3b5472b819847c8886caf163e3a4d23d53be7eadb02206c85c344281ffc17b0d0bdd8f4b3be3a14cf96375d3e1b9173395918e288ebf901"
    }
  ],
  "out": [
    {
      "value": "0.44950000",
      "scriptPubKey": "OP_DUP OP_HASH160 d4339bbd21720095c6842af39ae64c39666bf65c OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.80000000",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "1.59950000",
      "scriptPubKey": "OP_DUP OP_HASH160 495b82baffbe66589faa94cc1edee46aa8272032 OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.20000000",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    }
  ]
}

AliceBobNico corp. 发送给Satoshi

Alice,Bob,NicoAliceBobNico公司的创始人。他们同意将公司的资黄金存储在multi sig中,因此至少有两名出资人需要同意花钱。

让我们创建AliceBobNico的scriptPubKey,这是发送资黄金所必要的。

Script AliceBobNicoCorp = PayToMultiSigTemplate
                        .Instance
                        .GenerateScriptPubKey(2, new[] { alice.Key.PubKey, bob.Key.PubKey, nico.Key.PubKey });

这给了我们存储公司资黄金的multi sig脚本:

2 036d1b36a3a779b12f18c637e7c3ecaf0dfa08699eee276b61d169fc3521f391e6 02e49a9a8f28dc8ef8f9987d8e04d8294abadee5db1fef3b7db699b4b7c0964d28 028c018fdcaec8cef2d02ae0af19e4d9bf14cf6845c0445741bef5a79c44313f41 3 OP_CHECKMULTISIG

我们用一些硬币为这个地址提供资黄金,就像我们之前为鲍勃和艾丽斯所做的那样。

Transaction corpFunding = new Transaction()
{
    Outputs =
    {
        new TxOut("10", AliceBobNicoCorp),
        new TxOut("12", AliceBobNicoCorp),
        new TxOut("20", AliceBobNicoCorp)
    }
};
Coin[] corpCoins = corpFunding
                        .Outputs
                        .Select((o, i) => new Coin(new OutPoint(corpFunding.GetHash(), i), o))
                        .ToArray();

所以现在,AliceBobNico想把钱汇给Satoshi。然而,Bob不在办公室,Nico正在旅行,只有Alice留在办公室。所以Alice除了部分签署交易之外别无他法,然后通过电子邮件将其发送给Nico,以便他也可以签字。

txBuilder = new TransactionBuilder();
tx = txBuilder
        .AddCoins(corpCoins)
        .AddKeys(alice.Key)
        .Send(satoshi.GetAddress(), "4.5")
        .SetChange(AliceBobNicoCorp)
        .BuildTransaction(true);
Assert(!txBuilder.Verify(tx)); //Well, only one signature on the two required...

//Alice sends to Nico
txBuilder = new TransactionBuilder();
tx = txBuilder
        .AddCoins(corpCoins)
        .AddKeys(nico.Key)
        .SignTransaction(tx);
Assert(txBuilder.Verify(tx));

关键是TransactionBuilder将尽其所能用所知道的密钥签名。因此,您可以在同一个事务中混合使用所有类型的支出,并请求TransactionBuilder尽可能地解决混乱问题。

P2SH支付

AliceBobNico公司 发送给Satoshi

AliceBobNico的大部分客户都不支持以前的本地多重签名来进行脚本付款。

为了向AliceBobNico汇款,客户更愿意拥有一个简单的地址,而不是一个没有钱包支持的复杂的比特币脚本。

因此,AliceBobNico将其脚本转换为ScriptAddress,并将其交给客户。

var aliceBobNicoAddress = AliceBobNicoCorp.GetScriptAddress(Network.Main);

这给了我们3FNCyS4ugTCV8XZWV7SRENUG31fe8uUkFU即脚本地址。

让我们用AliceBobNico向客户发送一枚硬币:

Transaction corpFundingP2SH = new Transaction()
{
    Outputs =
    {
        new TxOut("40", aliceBobNicoAddress)
    }
};
Coin[] corpCoinsP2SH = corpFundingP2SH
                        .Outputs
                        .Select((o, i) => new ScriptCoin(new OutPoint(corpFundingP2SH.GetHash(), i), o, AliceBobNicoCorp))
                        .ToArray();

请注意,我使用的是ScriptCoin而不是简单的Coin,原因是TransactionBuilder需要ScriptAddress后面的真实Script(称为Redeem Script)才能正确签名。(在我们的例子中,它是前一部分中的multi sig脚本)

AliceBobNico想要发送45 BTC到Satoshi。所以它将需要前一部分的原生多multi sig 硬币,而且还需要从客户处收到的P2SH的multi sig类型的40 BTC。

txBuilder = new TransactionBuilder();
tx = txBuilder
        .AddCoins(corpCoins)
        .AddCoins(corpCoinsP2SH)
        .AddKeys(alice.Key, bob.Key)
        .Send(satoshi.GetAddress(), "45")
        .SetChange(aliceBobNicoAddress)
        .BuildTransaction(true);
Assert(txBuilder.Verify(tx));

这给了我们下面的交易,它结合了P2SH和原生multi sig!

{
  "hash": "1beb8e6b4b7b48c055a320017d3e170f37c8b5f0496c5e12e15e3f116e76ea22",

  "in": [
    {
      "prev_out": {
        "hash": "46f6fa184e6389ef59d66bb541513f38f15ff4a17fb16980e9cff98a6a623e7f",
        "n": 0
      },
      "scriptSig": "0 304402205c15f56d7bb08d1ba46da2a97ecd59e28a712627153c4d52efd717e2781d786902206c8d720ddc795348f1c05efc98143fb4df1319ba271a12580ae58c7e0b8dbc2d01 30440220591760c20ae69de43a301ae89e9208f33e95074bb1412af7c3fd07f9d31e017e022059ddef2f8d4b916b6df1851083b93d38059a0563ec393f4361a5cec4d8ac2dd501"
    },
    {
      "prev_out": {
        "hash": "46f6fa184e6389ef59d66bb541513f38f15ff4a17fb16980e9cff98a6a623e7f",
        "n": 1
      },
      "scriptSig": "0 3045022100edc9a6937f543790e25133b868c0578b1e3811434c375fe79009e9f5a8c5953202205db08237cbd6e97263117b40cf85067fe19a0cfa082a86b7ef1afe3e0a53425a01 3045022100941c219799b83315adaba7bd6720883791e657c8436d647ab4d562ccd97845a802202a3af553b810a30f880f9a5beb7d8369c8f96a084610cce3a986ee7b9ea6480701"
    },
    {
      "prev_out": {
        "hash": "46f6fa184e6389ef59d66bb541513f38f15ff4a17fb16980e9cff98a6a623e7f",
        "n": 2
      },
      "scriptSig": "0 304402200737866cda75fff1eb17ae1127e8a6c60ea7754a839f406e103bbf72582a5cdd0220178b706008a666433bffee63de7fb719a4997c6b027d0390b5707071a49299c801 3044022030d27da1c0115a11477c60bcffca7b0038baaea50835e33e2e5f8f18a876e35a02207e3b88d1a0070f5a7a8fb322849aa56604f7797cb51967830c215de670caa54301"
    },
    {
      "prev_out": {
        "hash": "81aefa18ce1e1aded705638eae772a149dc66eb8e44cf9ee30c5adcb43e06216",
        "n": 0
      },
      "scriptSig": "0 3045022100b49bcad7ac66b6f60606ab07c516000561d9816fe1f8f5fd54948a6a549204d002204bd25b5f8611f189ca404d537f65dac938122879d4b282d412f0c8b2d32285c201 3045022100e697655f6824906ea8adb935bbeffa301a20d5dbc4ae8ac24d568b44801bdda002200d01a493810bc19a5d6b269321e9a05047f7c520ad3609986681da2e67537c1601 5221036d1b36a3a779b12f18c637e7c3ecaf0dfa08699eee276b61d169fc3521f391e62102e49a9a8f28dc8ef8f9987d8e04d8294abadee5db1fef3b7db699b4b7c0964d2821028c018fdcaec8cef2d02ae0af19e4d9bf14cf6845c0445741bef5a79c44313f4153ae"
    }
  ],
  "out": [
    {
      "value": "37.00000000",
      "scriptPubKey": "OP_HASH160 960314e508ba47cf7331e25482b6adab2e1b7fe7 OP_EQUAL"
    },
    {
      "value": "45.00000000",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    }
  ]
}

隐形付款

DarkSatoshi将钱汇给DarkBob和Alice

由于之前文章中已经解释过的原因,DarkSatoshi想要一种方法来接受和使用StealthCoin,因此区块链的外部观察者不可能通过污染(识别)来构成他的钱包的地址。 TransactionBuilder也支持多sigig Stealth Address。

使用DarkAliceBobNico Corp.留作一个练习!(也有部分签名)

那么,在这里,我会向你介绍DarkBobDarkSatoshi

var darkSatoshiScan = new BitcoinSecret("KzosPd4rMJvZCfkP6nSfb1NEiC5mqMLZ5wUTv4CX4t3k73AtieyS");
var darkSatoshiKey = new BitcoinSecret("KxAWjXqVkGuGduYmc1ESBbBiCsTQiw56br1p5RnwLSKknfykCmwr");
var darkSatoshiAddress =
        new BitcoinStealthAddress(
            darkSatoshiScan.Key.PubKey,
            new[] { darkSatoshiKey.Key.PubKey },
            1,
            new BitField(3, 3),
            Network.Main);

var darkBobScan = new BitcoinSecret("L2KMQVEv6SJMQiHKPaugoAbNCLJk3faAcMr9JZaPoVMRL2XAVGXj");
var darkBobKey = new BitcoinSecret("L2kPJ2rduUTABExr3D1kPF1DrLP4b3dp1FmcxKhE3kd8iagbCq5Q");
var darkBobAddress =
        new BitcoinStealthAddress(
            darkBobScan.Key.PubKey,
            new[] { darkBobKey.Key.PubKey },
            1,
            new BitField(3, 3),
            Network.Main);

让我们资助DarkSatoshi

Transaction darkSatoshiFunding = new Transaction();
darkSatoshiAddress.CreatePayment().AddToTransaction(darkSatoshiFunding, "2.5");

这给了我们一个隐形交易。

{
  "hash": "f94b81bfc90f735b1284959cb6c1afd12c1d5cc01e19c31b6832b0acb9d21e20",
  "ver": 1,
  "vin_sz": 0,
  "vout_sz": 2,
  "lock_time": 0,
  "size": 93,
  "in": [],
  "out": [
    {
      "value": "0.00000000",
      "scriptPubKey": "OP_RETURN 0601000000026eb83a8483614c4670de94364cbcd794c9bc6315a26b8c8b756a7f13e49f814a"
    },
    {
      "value": "2.50000000",
      "scriptPubKey": "OP_DUP OP_HASH160 55965be7f26e287d6e09af43188e2fb1b62e0d15 OP_EQUALVERIFY OP_CHECKSIG"
    }
  ]
}

拥有BitcoinStealthAddressScanKey的人可以从中取出隐形硬币。

var darkSatoshiCoin = StealthCoin.Find(darkSatoshiFunding, darkSatoshiAddress, darkSatoshiScan.Key);

现在DarkSatoshi会把钱汇给DarkBobAlice

txBuilder = new TransactionBuilder();
tx = txBuilder
    .AddCoins(darkSatoshiCoin)
    .AddKeys(darkSatoshiKey.Key, darkSatoshiScan.Key)
    .Send(darkBobAddress, "1.0")
    .Send(alice.GetAddress(), "0.5")
    .SetChange(satoshi.GetAddress()) //Well… maybe not the best idea since it leaks some privacy
    .SendFees("0.01")
    .BuildTransaction(true);
Assert(txBuilder.Verify(tx));

而且反过来,由于他的scan key(扫描钥)和addresss(地址),DarkBob可以获得此交易的StealthCoin

var darkBobCoin = StealthCoin.Find(tx, darkBobAddress, darkBobScan.Key);
Assert(darkBobCoin != null);

Colored Coins付款

GoldGuy向Nico和Satoshi发出黄黄金,SilverGuy向Alice发出白银

您可以在Open Asset中执行的两项基本操作是发放资产并将其转移。但在转移之前,我们需要先发出。

我为您介绍GoldGuySilverGuy,与神般的力量去凭空创造黄黄金和白银(...好吧,更准确地说,从薄薄的dust中,就像你看到的)。

var goldGuy = new BitcoinSecret("KyuzoVnpsqW529yzozkzP629wUDBsPmm4QEkh9iKnvw3Dy5JJiNg");
var silverGuy = new BitcoinSecret("L4KvjpqDtdGEn7Lw6HdDQjbg74MwWRrFZMQTgJozeHAKJw5rQ2Kn");

对于发布资产,GoldGuy(和SilverGuy一样)必须花费我所说的IssuanceCoin,通常这种硬币具有BTC或多于或少于600 Satoshi的量,误差小于百分之一。

这种硬币的唯一目的是证明资产发行权的所有权。

IssuanceCoin中的 AssetId是从其ScriptPubKey中的哈希导出的,如在说明书中解释的那样。

以下是我如何为SatoshiNico创建我的IssuanceCoins,就像一些通常的Coin,我们将在稍后使用。

var issuanceCoinsTransaction
    = new Transaction()
    {
        Outputs =
        {
            new TxOut("1.0", goldGuy.Key.PubKey),
            new TxOut("1.0", silverGuy.Key.PubKey),
            new TxOut("1.0", nico.Key.PubKey),
            new TxOut("1.0", satoshi.Key.PubKey),
        }
    };

IssuanceCoin[] issuanceCoins = issuanceCoinsTransaction 
                        .Outputs 
                        .Take(2) 
                        .Select((o, i) => new Coin(new OutPoint(issuanceCoinsTransaction.GetHash(), i), o))
                        .Select(c => new IssuanceCoin(c))
                        .ToArray();

var goldIssuanceCoin = issuanceCoins[0]; 
var silverIssuanceCoin = issuanceCoins[1]; 
var nicoCoin = new Coin(new OutPoint(issuanceCoinsTransaction, 2), issuanceCoinsTransaction.Outputs[2]); 
var satoshiCoin = new Coin(new OutPoint(issuanceCoinsTransaction, 3), issuanceCoinsTransaction.Outputs[3]);

var goldId = goldIssuanceCoin.AssetId; 
var silverId = silverIssuanceCoin.AssetId;

给定一个交易,如果你想知道哪些资产被转移和发行,你需要知道其所有的祖先,直到追溯到issuanceCoinsTransaction。这就是为什么我会在TransactionRepository中跟踪这些转换。

var txRepo = new NoSqlTransactionRepository();
txRepo.Put(issuanceCoinsTransaction.GetHash(), issuanceCoinsTransaction);

但是,因为我们不希望我们每次请求ColoredTransaction时评估交易的所有祖先,我们还可以使用一个ColoredTransactionRepository,跟踪已经处理的ColoredTransaction

var ctxRepo = new NoSqlColoredTransactionRepository(txRepo);

好吧,现在让我们向NicoSatoshi发行一些*黄金*,看看我们是否正确地发布了资产。

txBuilder = new TransactionBuilder();
tx = txBuilder
    .AddKeys(goldGuy.Key)
    .AddCoins(goldIssuanceCoin)
    .IssueAsset(satoshi.GetAddress(), new Asset(goldId, 20))
    .IssueAsset(nico.GetAddress(), new Asset(goldId, 30))
    .SetChange(goldGuy.Key.PubKey)
    .BuildTransaction(true);
Assert(txBuilder.Verify(tx));
txRepo.Put(tx.GetHash(), tx);

var ctx = tx.GetColoredTransaction(ctxRepo);

这给了我们以下交易。

{
  "hash": "9384466f999c00e359e30bc382ac08145b77fe3229f19f6794c8c4bb58adec42",
  "ver": 1,
  "vin_sz": 1,
  "vout_sz": 4,
  "lock_time": 0,
  "size": 255,
  "in": [
    {
      "prev_out": {
        "hash": "bc74b0b15c8b1c526209632a7611930f72980641d94394d7dc3d07549d311a0e",
        "n": 0
      },
      "scriptSig": "3045022100ed0ce9377d9780256795a4b10d90f4ef0c2d82be6865835979784b7ccca0c8290220025e6121e7e8a2872ce36a83644921ec978db4474cd861e58ac700ac6f48cd2a01"
    }
  ],
  "out": [
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 1a9ba6e78130d5f1bcb6fc79e371511ccd19117b OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.99998800",
      "scriptPubKey": "031c99ad4cdfdd46b1867a9bef22d61b31ad6ca69ba1795285f7462e6a2c4eb357 OP_CHECKSIG"
    },
    {
      "value": "0.00000000",
      "scriptPubKey": "OP_RETURN 4f41010002141e00"
    }
  ]
}

这代表以下ColoredTransaction

{
  "inputs": [],
  "issuances": [
    {
      "index": 0,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 20
    },
    {
      "index": 1,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 30
    }
  ],
  "transfers": [],
  "destructions": []
}

所以第一个TxOut有20个 黄金,第二个有30个 黄金。因此,SatoshiNico现在将获得他们可以稍后花费的ColoredCoin

var coloredCoins = ColoredCoin.Find(tx, ctx).ToArray();
var satoshiGold = coloredCoins[0];
var nicoGold = coloredCoins[1];

现在让我们把白银发给Alice

txBuilder = new TransactionBuilder();
tx = txBuilder
    .AddKeys(silverGuy.Key)
    .AddCoins(silverIssuanceCoin)
    .IssueAsset(alice.GetAddress(), new Asset(silverId, 10))
    .SetChange(silverGuy.Key.PubKey)
    .BuildTransaction(true);
Assert(txBuilder.Verify(tx));
txRepo.Put(tx.GetHash(), tx);

var aliceSilver = ColoredCoin.Find(tx, ctxRepo).First();

Nico将黄金发送给Satoshi

Nico希望发送1个黄金Satoshi

txBuilder = new TransactionBuilder();
tx = txBuilder
    .AddCoins(nicoGold)
    .AddKeys(nico.Key)
    .SendAsset(satoshi.GetAddress(), new Asset(goldId, 1))
    .SetChange(nico.GetAddress())
    .BuildTransaction(true);
Assert(txBuilder.Verify(tx));
txRepo.Put(tx.GetHash(), tx);

ctx = tx.GetColoredTransaction(ctxRepo);

这给了我们下面的ColoredTransaction

{
  "inputs": [
    {
      "index": 0,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 30
    }
  ],
  "issuances": [],
  "transfers": [
    {
      "index": 1,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 29
    },
    {
      "index": 2,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 1
    }
  ],
  "destructions": []
}

29 黄金被交还给Nico,1个被送到了Satoshi

Satoshi和Alice希望将黄金兑换成白银和BTC

Satoshi希望获得Alice白银:10 黄金*兑换9 白银** + 0.5 BTC。

这样的例子是在一行中完成的,但是SatoshiAlice也可以用我之前提到的多信用付款的相同流程独立签署交易。

普通的Coin是支付TXOUTDust所必须的,它承载了Colored Coins。

txBuilder = new TransactionBuilder();
tx = txBuilder
        .AddCoins(aliceSilver)
        .AddCoins(aliceCoins)
        .AddKeys(alice.Key)
        .SendAsset(satoshi.GetAddress(), new Asset(silverId, 9))
        .Send(satoshi.GetAddress(), "0.5")
        .SetChange(alice.GetAddress())
        .Then()
        .AddCoins(satoshiGold)
        .AddCoins(satoshiCoin)
        .AddKeys(satoshi.Key)
        .SendAsset(alice.GetAddress(), new Asset(goldId, 10))
        .SetChange(satoshi.GetAddress())
        .BuildTransaction(true);
Assert(txBuilder.Verify(tx));
txRepo.Put(tx.GetHash(), tx);

ctx = tx.GetColoredTransaction(ctxRepo);

结果是以下ColoredTransaction

{
  "inputs": [
    {
      "index": 0,
      "asset": "ATLqDUahLMs1Jj5yPVmyxEJH2WkkHZeFT5",
      "quantity": 10
    },
    {
      "index": 2,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 20
    }
  ],
  "issuances": [],
  "transfers": [
    {
      "index": 1,
      "asset": "ATLqDUahLMs1Jj5yPVmyxEJH2WkkHZeFT5",
      "quantity": 1
    },
    {
      "index": 2,
      "asset": "ATLqDUahLMs1Jj5yPVmyxEJH2WkkHZeFT5",
      "quantity": 9
    },
    {
      "index": 5,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 10
    },
    {
      "index": 6,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 10
    }
  ],
  "destructions": []
}

对于以下交易:

{
  "hash": "d678dc8f1595d064990e9d49dfa25260ab414b8b26a87a12e1f15c52a79a2d05",
  "ver": 1,
  "vin_sz": 4,
  "vout_sz": 8,
  "lock_time": 0,
  "size": 792,
  "in": [
    {
      "prev_out": {
        "hash": "ef6dbcacb3aae5c676a9fcefd31ba5c5c8d2df4c604b1b98393ded3a06ea2031",
        "n": 0
      },
      "scriptSig": "30440220392a85cfe9f394bcaf4814fc7f8de055db9e028690313c95fc59537de3f2bff8022057b6c61b75c80dbf88d91aa0769e3630d9d1248ea5103b4df9f9a3f5288b4cdb01 036d1b36a3a779b12f18c637e7c3ecaf0dfa08699eee276b61d169fc3521f391e6"
    },
    {
      "prev_out": {
        "hash": "920edde4ef144b8242d9bc82cef7186d552e06b30443aef1888ac6e4eb868ebf",
        "n": 1
      },
      "scriptSig": "3044022024db80a8c9fb5033d6369f9ec1ff8893c32a8cc6235f84cb06fc93c7e256853802207a30cff0a7a7a5939724158d5a08f084c4139ec80ce80488b38e084427c0c0e101"
    },
    {
      "prev_out": {
        "hash": "9384466f999c00e359e30bc382ac08145b77fe3229f19f6794c8c4bb58adec42",
        "n": 0
      },
      "scriptSig": "3045022100f209aa198f13651f84f2287e037d64f9a8b2a413f6072b034e0bdd8e5ed47b2f02206eb5b32803e4c12234a58762b84732b4b84148a71b01e13e1dc62feac52e5ad901 0211f452e6ed4daf193c3f1b3652e289ad57567e5e816f050e2116541a32098f15"
    },
    {
      "prev_out": {
        "hash": "bc74b0b15c8b1c526209632a7611930f72980641d94394d7dc3d07549d311a0e",
        "n": 3
      },
      "scriptSig": "3044022015c9ebf6a1f6361075b3f5dddd9feb7722d1f3a7f3e605580523e1fc195a553702207106a382416d03b67e5a8ef46f3b63c06d6d732756deb866fc071803449b207a01"
    }
  ],
  "out": [
    {
      "value": "0.00000000",
      "scriptPubKey": "OP_RETURN 4f41010006010900000a0a00"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 d4339bbd21720095c6842af39ae64c39666bf65c OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.29999400",
      "scriptPubKey": "OP_DUP OP_HASH160 d4339bbd21720095c6842af39ae64c39666bf65c OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.50000000",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 d4339bbd21720095c6842af39ae64c39666bf65c OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.99999400",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    }
  ]
}

正如你所看到的,资产和BTC的更改被正确地发回给每个所有者。

地狱交易(仅适用于勇士)

GoldGuySilverGuy同意发出铂金Satoshi

Satoshi想要用铂金Alice白银交易,跟Nico黄金*交易,跟DarkBob的BTC和 AliceBobNico** CORP的BTC 交易。

第一,用于发出铂金,我们将需要GoldGuySilverGuy之间发行multi sig。

首先让我们为他们创建一个P2SH地址。

var platiniumRedeem = PayToMultiSigTemplate.Instance
                            .GenerateScriptPubKey(2, new[] { goldGuy.Key.PubKey, silverGuy.Key.PubKey });
var platiniumAddress = platiniumRedeem.GetScriptAddress(Network.Main);

让我们资助他们一些IssuanceCoin吧

var issuancePlatiniumCoinsTransaction
    = new Transaction()
    {
        Outputs =
        {
            new TxOut("1.0", platiniumAddress),
        }
    };

txRepo.Put(issuancePlatiniumCoinsTransaction.GetHash(), issuancePlatiniumCoinsTransaction);

IssuanceCoin issuancePlatiniumCoin = issuanceCoinsTransaction
                        .Outputs
                        .Select((o, i) => new Coin(new OutPoint(issuanceCoinsTransaction.GetHash(), i), o))
                        .Select(c => new IssuanceCoin(c))
                        .First();
var platiniumId = issuancePlatiniumCoin.AssetId;

让我们发送15个PlatiniumSatoshi

txBuilder = new TransactionBuilder();
tx = txBuilder
    .AddKeys(goldGuy.Key, silverGuy.Key)
    .AddCoins(issuancePlatiniumCoin)
    .IssueAsset(satoshi.GetAddress(), new Asset(platiniumId, 10))
    .SetChange(platiniumAddress)
    .BuildTransaction(true);
Assert(txBuilder.Verify(tx));
txRepo.Put(tx.GetHash(), tx);
ctx = tx.GetColoredTransaction(ctxRepo);
var satoshiPlatinium = ColoredCoin.Find(tx, ctx).First();

现在,让我们达成交易:

Satoshi想要用5个白黄金Alice的3个白银Nico的2个黄金*, DarkBob的0.2个BTC以及 AliceBobNico** CORP的2个 BTC。

再次强调,交易可以创建,然后由所有参与者独立签署。但对于这篇文章,我只用一行代码来完成。

txBuilder = new TransactionBuilder();
tx = txBuilder
        .AddKeys(satoshi.Key)
        .AddCoins(satoshiPlatinium)
        .AddCoins(satoshiCoin)
        .SendAsset(nico.GetAddress(), new Asset(platiniumId, 3))
        .SendAsset(alice.GetAddress(), new Asset(platiniumId, 2))
        .SetChange(satoshi.GetAddress())
        .Then()
        .AddKeys(alice.Key)
        .AddCoins(aliceSilver)
        .AddCoins(aliceCoins)
        .SendAsset(satoshi.GetAddress(), new Asset(silverId, 3))
        .SetChange(alice.GetAddress())
        .Then()
        .AddCoins(nicoGold)
        .AddCoins(nicoCoin)
        .SendAsset(satoshi.GetAddress(), new Asset(goldId, 2))
        .SetChange(nico.GetAddress())
        .Then()
        .AddCoins(darkBobCoin)
        .AddKeys(darkBobKey, darkBobScan)
        .Send(satoshi.GetAddress(), "0.5")
        .SetChange(bob.GetAddress())
        .Then()
        .AddCoins(corpCoins)
        .AddKeys(nico.Key, alice.Key)
        .Send(satoshi.GetAddress(), "2.0")
        .SetChange(AliceBobNicoCorp)
        .BuildTransaction(true);

txRepo.Put(tx.GetHash(), tx);
ctx = tx.GetColoredTransaction(ctxRepo);

这给了我们预期的ColoredTransaction ;

{
  "inputs": [
    {
      "index": 0,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 10
    },
    {
      "index": 2,
      "asset": "ATLqDUahLMs1Jj5yPVmyxEJH2WkkHZeFT5",
      "quantity": 10
    },
    {
      "index": 4,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 30
    }
  ],
  "issuances": [],
  "transfers": [
    {
      "index": 1,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 5
    },
    {
      "index": 2,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 3
    },
    {
      "index": 3,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 2
    },
    {
      "index": 5,
      "asset": "ATLqDUahLMs1Jj5yPVmyxEJH2WkkHZeFT5",
      "quantity": 7
    },
    {
      "index": 6,
      "asset": "ATLqDUahLMs1Jj5yPVmyxEJH2WkkHZeFT5",
      "quantity": 3
    },
    {
      "index": 8,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 28
    },
    {
      "index": 9,
      "asset": "AeRDfBJh5cXudMWu7XeHabopTB4fDkDph1",
      "quantity": 2
    }
  ],
  "destructions": []
}

以及预期的Transaction(交易)

{
  "hash": "a6c42499c91575815d026a12ce2bb54e2078c86941ac3202656e117a20a32d36",
  "ver": 1,
  "vin_sz": 8,
  "vout_sz": 15,
  "lock_time": 0,
  "size": 1742,
  "in": [
    {
      "prev_out": {
        "hash": "15e9a39a67f00d1a74830d60dc49732719ecc1d19038e594ea7f317fc3cea119",
        "n": 0
      },
      "scriptSig": "304402201d097ec16ea6d0cbcae662f34ec21350246f6d879b485511bb6ba6e382be6abe022016b1d645cdce32b482efdc25007daeca5af292f9c8bda3a85670edf44db182b401 0211f452e6ed4daf193c3f1b3652e289ad57567e5e816f050e2116541a32098f15"
    },
    {
      "prev_out": {
        "hash": "bc74b0b15c8b1c526209632a7611930f72980641d94394d7dc3d07549d311a0e",
        "n": 3
      },
      "scriptSig": "30450221009f60c5d42ad8c0e53e5e0f569305bb64bd075f8ef33157172821c411853b2b2f02203f312d61667f736c6eeb77054990a03204f12d824f5535117cfc20f2278a945401"
    },
    {
      "prev_out": {
        "hash": "ef6dbcacb3aae5c676a9fcefd31ba5c5c8d2df4c604b1b98393ded3a06ea2031",
        "n": 0
      },
      "scriptSig": "3045022100df1ab213838f819ff43e74a3c1972aeed92ab17b0e27a04df8ec5b3b1eadd9ea02205fcefe55a4db243d1aac546839f33bdf3120041f9086bc218d60814f457221f501 036d1b36a3a779b12f18c637e7c3ecaf0dfa08699eee276b61d169fc3521f391e6"
    },
    {
      "prev_out": {
        "hash": "920edde4ef144b8242d9bc82cef7186d552e06b30443aef1888ac6e4eb868ebf",
        "n": 0
      },
      "scriptSig": "304402200a2d4206b24a8276ff30aaffd2a81443241ec810370c4fbdc70b288cfa7c3488022071cea67bee407a9d13014504c4df5966b011da5c9f7dfbca8281b4d200531eff01 036d1b36a3a779b12f18c637e7c3ecaf0dfa08699eee276b61d169fc3521f391e6"
    },
    {
      "prev_out": {
        "hash": "9384466f999c00e359e30bc382ac08145b77fe3229f19f6794c8c4bb58adec42",
        "n": 1
      },
      "scriptSig": "30440220549292b1f9f0df4956f575832433ff0b2c4de922686ee611b2fc4491617fdb6f02205ebfc38907d9717944ca655b075188be359191a0b038a2e53e0835870ed9565b01 028c018fdcaec8cef2d02ae0af19e4d9bf14cf6845c0445741bef5a79c44313f41"
    },
    {
      "prev_out": {
        "hash": "bc74b0b15c8b1c526209632a7611930f72980641d94394d7dc3d07549d311a0e",
        "n": 2
      },
      "scriptSig": "304402201902dc60304b1c49ace591edc35380d970b5f426084147ad252ed567b66c323902206d54089cc85a1ee0474f993451a0e862ab88854fa4ea220b4a642d2c79ca596601"
    },
    {
      "prev_out": {
        "hash": "718f4a3d91ad1a914bce857183ac910d5d6440016f5e72b910db99de5e11ed97",
        "n": 2
      },
      "scriptSig": "3044022044cf065a256cfadf505e1e96f225d6952a4293a89f748fd889370847280f9ce5022008d8755d237b6b7cc9ed4b8e909dc27db8afb5ee52e2ce8532e494f90ca0ed5501 0227fa95b82a3ee4036f7581859afaa852a5ad1da34015b0ef09948b1babf4675a"
    },
    {
      "prev_out": {
        "hash": "46f6fa184e6389ef59d66bb541513f38f15ff4a17fb16980e9cff98a6a623e7f",
        "n": 0
      },
      "scriptSig": "0 30450221008acce661bdd08d3125473e87bfe002424ec8ea02e3932a0a78e3c701857846f502207e5207009a84b90ee9a281aef85a0d85e53ef39b56c403f1de717f5ec08962d801 304402200170c4b392e99cdd75321d2c02f5a32b78f7aa6f1ba555c40cb6a79ad0943d59022002299a2c785fa5fd683a227234bc567ffcc2ed8d265a64ae13ccce4c488a850901"
    }
  ],
  "out": [
    {
      "value": "0.00000000",
      "scriptPubKey": "OP_RETURN 4f41010009050302000703001c0200"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 1a9ba6e78130d5f1bcb6fc79e371511ccd19117b OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 d4339bbd21720095c6842af39ae64c39666bf65c OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.99998800",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 d4339bbd21720095c6842af39ae64c39666bf65c OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.44999400",
      "scriptPubKey": "OP_DUP OP_HASH160 d4339bbd21720095c6842af39ae64c39666bf65c OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 1a9ba6e78130d5f1bcb6fc79e371511ccd19117b OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.00000600",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.99999400",
      "scriptPubKey": "OP_DUP OP_HASH160 1a9ba6e78130d5f1bcb6fc79e371511ccd19117b OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.50000000",
      "scriptPubKey": "OP_DUP OP_HASH160 495b82baffbe66589faa94cc1edee46aa8272032 OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "0.50000000",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": "8.00000000",
      "scriptPubKey": "2 036d1b36a3a779b12f18c637e7c3ecaf0dfa08699eee276b61d169fc3521f391e6 02e49a9a8f28dc8ef8f9987d8e04d8294abadee5db1fef3b7db699b4b7c0964d28 028c018fdcaec8cef2d02ae0af19e4d9bf14cf6845c0445741bef5a79c44313f41 3 OP_CHECKMULTISIG"
    },
    {
      "value": "2.00000000",
      "scriptPubKey": "OP_DUP OP_HASH160 e4ac93b6d222020bd87b0e810b363f1ed0342ccb OP_EQUALVERIFY OP_CHECKSIG"
    }
  ]
}

完成!

结论

TransactionBuilder的创建受到bitcoinjs的启发。我相信一个重要的工具可以降低企业家进入比特币领域的障碍。交易签署一直是一个困难的过程,我希望我已经为你解决了这个问题!

本文的版权归 Steve Wang 所有,如需转载请联系作者。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏醒者呆

以太坊挖矿源码:ethash算法

本文具体分析以太坊的共识算法之一:实现了POW的以太坊共识引擎ethash。 关键字:ethash,共识算法,pow,Dagger Hashimoto,...

1.5K60
来自专栏HansBug's Lab

1740: [Usaco2005 mar]Yogurt factory 奶酪工厂

1740: [Usaco2005 mar]Yogurt factory 奶酪工厂 Time Limit: 5 Sec  Memory Limit: 64 MB ...

27750

了解与实现“工作量证明”的源头 Hashcash

让我们来看看 Hashcash 的思路:一封要证明其合法性的电子邮件需要附带一些对字符串的 hash 值来证明其耗费了一定的时间/资源运行了某个算法(Hashc...

443110
来自专栏月牙寂

[以太坊源代码分析]III. 挖矿和共识算法的奥秘

1.待挖掘区块需要组装 在Ethereum 代码中,名为miner的包(package)负责向外提供一个“挖矿”得到的新区块,其主要结构体的UML关系图如下...

48080
来自专栏WindCoder

Java设计模式学习笔记—建造者模式

文章最后“Java设计模式笔记示例代码整合”为本系列代码整合,所有代码均为个人手打并运行测试,不定期更新。本节内容位于其Builder包(package)中。

10520
来自专栏区块链大本营

继承变量覆盖及构造函数失配,竟然会导致这些漏洞

区块参数作为区块属性的数据,对于挖掘区块的矿工来说,并不具有完全的随机性,因此将其作为随机数生成的依据是有局限性和危险性的。而以太坊本身又没有提供类似于传统语言...

11120
来自专栏软件开发

一种绝对提高开发水平的方法

如果做了多年开发的你发现自己的水平一直上不去,你可能要提高自己的英文水平了,英语就是你技术的瓶颈,对有些人可能是硬伤。

48040
来自专栏区块链大本营

V神绞尽脑汁开发Vyper,Python、Solidity要失宠?十分钟,看完这份12岁儿童都能看懂的智能合约指南,你就明白了…

全新的以太坊语言Vyper已经发布,并在社交媒体上引起热议。Vyper是由废弃语言Serpent升级而来,为开发者们提供了可以替代Solidity语言的一种选择...

18030
来自专栏一个会写诗的程序员的博客

在 Java 9 的JShell中 跟Kotlin 的REPL中尽情体验函数式编程乐趣吧《Kotlin极简教程》正式上架:

相比之下, 我们不得不说,Java 8,9中的 Stream API 还是有点啰嗦,绕来绕去。不如Kotlin来得直截了当,简单优雅。

9810
来自专栏小樱的经验随笔

Vijos P1113 不高兴的津津【模拟】

不高兴的津津 描述 津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢...

27980

扫码关注云+社区

领取腾讯云代金券