Skip to content

Commit

Permalink
Methods for signing partially a transaction, v 1.0.5.8
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasDorier committed Oct 21, 2014
1 parent 01cf148 commit 553f773
Show file tree
Hide file tree
Showing 6 changed files with 369 additions and 5 deletions.
11 changes: 11 additions & 0 deletions NBitcoin.Tests/RepositoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,17 @@ public static void CanParseRev()
[Fact]
public static void Play()
{
var tx2 = new Transaction("010000000188932931d6bc23d3182183ab5e9707980ab4aaf9db3c6d3be42e5c0ce783b0ba00000000844730440220100aaa46e8a4f9d4589f935f5457f263a911f3712ee50688732c1274face6bb30220155b48760fd6ffbc0842761db03d824954567e8cd499883318d1f1c705f7d4d7012103dccb6bd324ae3c60afb85d9a0e5f300284faf2d71c40dbb7732d8fa79ee930f71976a914edc80be0e4f342a54a4fbe6e31e8e58b6849972a88acffffffff02204e0000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac70110100000000001976a914edc80be0e4f342a54a4fbe6e31e8e58b6849972a88ac00000000");

var oo = tx2.GetHash();


var scriptPubKey = new Script(Encoders.Hex.DecodeData("a91467c205a82218e3b1327095f1e10dd676c6ce09df87"));
ScriptEvaluationContext eval = new ScriptEvaluationContext();

var result = eval.VerifyScript(tx2.Inputs[0].ScriptSig, scriptPubKey, tx2, 0);



CancellationTokenSource s1 = new CancellationTokenSource();
CancellationTokenSource s2 = new CancellationTokenSource(TimeSpan.FromSeconds(1));
Expand Down
102 changes: 100 additions & 2 deletions NBitcoin.Tests/transaction_tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,104 @@ namespace NBitcoin.Tests
{
public class transaction_tests
{
[Fact]
[Trait("UnitTest", "UnitTest")]
public void CanSignTransaction()
{
var key = new Key();
PayToPubkeyHashTemplate template = new PayToPubkeyHashTemplate();
var scriptPubKey = template.GenerateScriptPubKey(key.PubKey);

Transaction tx = new Transaction();
tx.AddInput(new TxIn(new OutPoint(tx.GetHash(), 0)));
tx.AddInput(new TxIn(new OutPoint(tx.GetHash(), 1)));
tx.AddOutput(new TxOut("21", key.PubKey.ID));
tx.SignAll(key);

AssertCorrectlySigned(tx, scriptPubKey);
}

[Fact]
[Trait("UnitTest", "UnitTest")]
//https://gist.github.com/gavinandresen/3966071
public void CanPartiallySignTransaction()
{
var privKeys = new[]{"5JaTXbAUmfPYZFRwrYaALK48fN6sFJp4rHqq2QSXs8ucfpE4yQU",
"5Jb7fCeh1Wtm4yBBg3q3XbT6B525i17kVhy3vMC9AqfR6FH2qGk",
"5JFjmGo5Fww9p8gvx48qBYDJNAzR9pmH5S389axMtDyPT8ddqmw"}
.Select(k => new BitcoinSecret(k).Key).ToArray();

//First: combine the three keys into a multisig address
var multiSigTemplate = new PayToMultiSigTemplate();
var redeem = multiSigTemplate.GenerateScriptPubKey(2, privKeys.Select(k => k.PubKey).ToArray());
var scriptAddress = redeem.ID.GetAddress(Network.Main);
Assert.Equal("3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC", scriptAddress.ToString());

// Next, create a transaction to send funds into that multisig. Transaction d6f72... is
// an unspent transaction in my wallet (which I got from the 'listunspent' RPC call):
// Taken from example
var fundingTransaction = new Transaction("010000000189632848f99722915727c5c75da8db2dbf194342a0429828f66ff88fab2af7d6000000008b483045022100abbc8a73fe2054480bda3f3281da2d0c51e2841391abd4c09f4f908a2034c18d02205bc9e4d68eafb918f3e9662338647a4419c0de1a650ab8983f1d216e2a31d8e30141046f55d7adeff6011c7eac294fe540c57830be80e9355c83869c9260a4b8bf4767a66bacbd70b804dc63d5beeb14180292ad7f3b083372b1d02d7a37dd97ff5c9effffffff0140420f000000000017a914f815b036d9bbbce5e9f2a00abd1bf3dc91e955108700000000");

// Create the spend-from-multisig transaction. Since the fund-the-multisig transaction
// hasn't been sent yet, I need to give txid, scriptPubKey and redeemScript:
var spendTransaction = new Transaction();
spendTransaction.Inputs.Add(new TxIn()
{
PrevOut = new OutPoint(fundingTransaction.GetHash(), 0),
});
spendTransaction.Outputs.Add(new TxOut()
{
Value = "0.01000000",
ScriptPubKey = new Script("OP_DUP OP_HASH160 ae56b4db13554d321c402db3961187aed1bbed5b OP_EQUALVERIFY OP_CHECKSIG")
});

//... Now I can partially sign it using one private key:

var partiallySigned = spendTransaction.CreatePartiallySignedTransaction(redeem);
partiallySigned.SignAll(privKeys[0]);

//the other private keys (note the "hex" result getting longer):
partiallySigned.SignAll(privKeys[1]);

var signed = partiallySigned.BuildSignedTransaction();
AssertCorrectlySigned(signed, fundingTransaction.Outputs[0].ScriptPubKey);

//Verify the transaction from the gist is also correctly signed
var gistTransaction = new Transaction("0100000001aca7f3b45654c230e0886a57fb988c3044ef5e8f7f39726d305c61d5e818903c00000000fd5d010048304502200187af928e9d155c4b1ac9c1c9118153239aba76774f775d7c1f9c3e106ff33c0221008822b0f658edec22274d0b6ae9de10ebf2da06b1bbdaaba4e50eb078f39e3d78014730440220795f0f4f5941a77ae032ecb9e33753788d7eb5cb0c78d805575d6b00a1d9bfed02203e1f4ad9332d1416ae01e27038e945bc9db59c732728a383a6f1ed2fb99da7a4014cc952410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d4621353aeffffffff0140420f00000000001976a914ae56b4db13554d321c402db3961187aed1bbed5b88ac00000000");
AssertCorrectlySigned(gistTransaction, fundingTransaction.Outputs[0].ScriptPubKey);

//Can sign out of order
partiallySigned = spendTransaction.CreatePartiallySignedTransaction(redeem);
partiallySigned.SignAll(privKeys[2]);
partiallySigned.SignAll(privKeys[0]);
signed = partiallySigned.BuildSignedTransaction();
AssertCorrectlySigned(signed, fundingTransaction.Outputs[0].ScriptPubKey);

//Can clone partially signed transaction
partiallySigned = partiallySigned.Clone();
signed = partiallySigned.BuildSignedTransaction();
AssertCorrectlySigned(signed, fundingTransaction.Outputs[0].ScriptPubKey);

//Can sign multiple inputs
spendTransaction.Inputs.Add(new TxIn()
{
PrevOut = new OutPoint(fundingTransaction.GetHash(), 1),
});
partiallySigned = spendTransaction.CreatePartiallySignedTransaction(redeem);
partiallySigned.SignAll(privKeys[2]);
partiallySigned.SignAll(privKeys[0]);
signed = partiallySigned.BuildSignedTransaction();
AssertCorrectlySigned(signed, fundingTransaction.Outputs[0].ScriptPubKey);
}

private void AssertCorrectlySigned(Transaction tx, Script scriptPubKey)
{
for(int i = 0 ; i < tx.Inputs.Count ; i++)
{
Assert.True(Script.VerifyScript(tx.Inputs[i].ScriptSig, scriptPubKey, tx, i));
}
}

[Fact]
[Trait("UnitTest", "UnitTest")]
//http://brainwallet.org/#tx
Expand Down Expand Up @@ -260,15 +358,15 @@ private Transaction[] SetupDummyInputs(CoinsView coinsRet)
dummyTransactions[0].Outputs[0].ScriptPubKey = dummyTransactions[0].Outputs[0].ScriptPubKey + key[0].PubKey.ToBytes() + OpcodeType.OP_CHECKSIG;
dummyTransactions[0].Outputs[1].Value = 50 * Money.CENT;
dummyTransactions[0].Outputs[1].ScriptPubKey = dummyTransactions[0].Outputs[1].ScriptPubKey + key[1].PubKey.ToBytes() + OpcodeType.OP_CHECKSIG;
coinsRet.AddTransaction(dummyTransactions[0],0);
coinsRet.AddTransaction(dummyTransactions[0], 0);


dummyTransactions[1].Outputs.AddRange(Enumerable.Range(0, 2).Select(_ => new TxOut()));
dummyTransactions[1].Outputs[0].Value = 21 * Money.CENT;
dummyTransactions[1].Outputs[0].ScriptPubKey = StandardScripts.PayToAddress(key[2].PubKey.GetAddress(Network.Main));
dummyTransactions[1].Outputs[1].Value = 22 * Money.CENT;
dummyTransactions[1].Outputs[1].ScriptPubKey = StandardScripts.PayToAddress(key[3].PubKey.GetAddress(Network.Main));
coinsRet.AddTransaction(dummyTransactions[1],0);
coinsRet.AddTransaction(dummyTransactions[1], 0);


return dummyTransactions;
Expand Down
2 changes: 1 addition & 1 deletion NBitcoin/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.5.7")]
[assembly: AssemblyVersion("1.0.5.8")]
[assembly: AssemblyFileVersion("1.0.0.0")]
8 changes: 7 additions & 1 deletion NBitcoin/PubKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,13 @@ public byte[] ToBytes()
{
return vch.ToArray();
}

public byte[] ToBytes(bool @unsafe)
{
if(@unsafe)
return vch;
else
return vch.ToArray();
}
public override string ToString()
{
return ToHex();
Expand Down
5 changes: 5 additions & 0 deletions NBitcoin/Script.cs
Original file line number Diff line number Diff line change
Expand Up @@ -729,5 +729,10 @@ public static Script CreateFromDestinationAddress(BitcoinAddress address)
{
return CreateFromDestination(address.ID);
}

public static bool IsNullOrEmpty(Script script)
{
return script == null || script._Script.Length == 0;
}
}
}

0 comments on commit 553f773

Please sign in to comment.