Skip to content

Commit

Permalink
Refactoring and rewriting helper methods in Script, 1.0.5.5
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasDorier committed Sep 26, 2014
1 parent 5a337b6 commit 6b2e88c
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 37 deletions.
4 changes: 2 additions & 2 deletions NBitcoin.Tests/ColoredCoinsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ public void CanCreateAssetAddress()
var address = key.PubKey.Decompress().GetAddress(Network.Main);
Assert.Equal("16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", address.ToString());

Script script = Script.FromBitcoinAddress(address);
Script script = Script.CreateFromDestinationAddress(address);
Assert.Equal("OP_DUP OP_HASH160 010966776006953D5567439E5E39F86A0D273BEE OP_EQUALVERIFY OP_CHECKSIG", script.ToString().ToUpper());

var scriptAddress = script.GetAddress(Network.Main);
var scriptAddress = script.GetScriptAddress(Network.Main);
Assert.Equal("36hBrMeUfevFPZdY2iYSHVaP9jdLd9Np4R", scriptAddress.ToString());
}

Expand Down
37 changes: 37 additions & 0 deletions NBitcoin.Tests/script_tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,43 @@ public void CanParseAndGeneratePayToMultiSig()
Assert.Equal(scriptSig, template.GenerateScriptSig(result).ToString());
}

[Fact]
[Trait("UnitTest", "UnitTest")]
public void CanExtractAddressesFromScript()
{
var payToMultiSig = new Script("1 0364bd4b02a752798342ed91c681a48793bb1c0853cbcd0b978c55e53485b8e27c 0364bd4b02a752798342ed91c681a48793bb1c0853cbcd0b978c55e53485b8e27d 2 OP_CHECKMULTISIG");

Assert.Null(payToMultiSig.GetSigner());
var destinations = payToMultiSig.GetDestinations();
Assert.Equal(2, destinations.Length);
Assert.Equal(new PubKey("0364bd4b02a752798342ed91c681a48793bb1c0853cbcd0b978c55e53485b8e27c").ID, destinations[0]);
Assert.Equal(new PubKey("0364bd4b02a752798342ed91c681a48793bb1c0853cbcd0b978c55e53485b8e27d").ID, destinations[1]);

var payToScriptHash = new Script("OP_HASH160 b5b88dd9befc9236915fcdbb7fd50052df50c855 OP_EQUAL");
Assert.NotNull(payToScriptHash.GetDestination());
Assert.IsType<ScriptId>(payToScriptHash.GetDestination());
Assert.Equal("b5b88dd9befc9236915fcdbb7fd50052df50c855", payToScriptHash.GetDestination().ToString());
Assert.True(payToScriptHash.GetDestination().GetAddress(Network.Main).GetType() == typeof(BitcoinScriptAddress));

var payToPubKeyHash = new Script("OP_DUP OP_HASH160 356facdac5f5bcae995d13e667bb5864fd1e7d59 OP_EQUALVERIFY OP_CHECKSIG");
Assert.NotNull(payToPubKeyHash.GetDestination());
Assert.IsType<KeyId>(payToPubKeyHash.GetDestination());
Assert.Equal("356facdac5f5bcae995d13e667bb5864fd1e7d59", payToPubKeyHash.GetDestination().ToString());
Assert.True(payToPubKeyHash.GetDestination().GetAddress(Network.Main).GetType() == typeof(BitcoinAddress));

var p2shScriptSig = new Script("0 3044022064f45a382a15d3eb5e7fe72076eec4ef0f56fde1adfd710866e729b9e5f3383d02202720a895914c69ab49359087364f06d337a2138305fbc19e20d18da78415ea9301 51210364bd4b02a752798342ed91c681a48793bb1c0853cbcd0b978c55e53485b8e27c210364bd4b02a752798342ed91c681a48793bb1c0853cbcd0b978c55e53485b8e27d52ae");

Assert.NotNull(p2shScriptSig.GetSigner());
Assert.IsType<ScriptId>(p2shScriptSig.GetSigner());
Assert.Equal("b5b88dd9befc9236915fcdbb7fd50052df50c855", p2shScriptSig.GetSigner().ToString());

var p2phScriptSig = new Script("3045022100af878a48aab5a71397d518ee1ae3c35267cb559240bc4a06926d65d575090e7f02202a9208e1f13683b4e450b349ae3e7bd4498d5d808f06c4b8059ea41595447af401 02a71e88db4924c7620f3b27fa748817444b6ad02cd8cea32ed3cf2deb8b5ccae7");

Assert.NotNull(p2phScriptSig.GetSigner());
Assert.IsType<KeyId>(p2phScriptSig.GetSigner());
Assert.Equal("352183abbcc80a0cd7c051a28df0abbf1e80ac3e", p2phScriptSig.GetSigner().ToString());
}


[Fact]
[Trait("UnitTest", "UnitTest")]
Expand Down
12 changes: 12 additions & 0 deletions NBitcoin/BitcoinAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,17 @@ public override Base58Type Type
return Base58Type.PUBKEY_ADDRESS;
}
}

public static BitcoinAddress Create(TxDestination id, Network network)
{
if(network == null)
throw new ArgumentNullException("network");
if(id is KeyId)
return new BitcoinAddress(id, network);
else if(id is ScriptId)
return new BitcoinScriptAddress((ScriptId)id, network);
else
throw new NotSupportedException();
}
}
}
5 changes: 5 additions & 0 deletions NBitcoin/KeyId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public TxDestination(string value)
_Dest = value;
}

public BitcoinAddress GetAddress(Network network)
{
return BitcoinAddress.Create(this, network);
}

public virtual Script CreateScriptPubKey()
{
return null;
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.4")]
[assembly: AssemblyVersion("1.0.5.5")]
[assembly: AssemblyFileVersion("1.0.0.0")]
6 changes: 3 additions & 3 deletions NBitcoin/RPC/SatoshiFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,15 @@ protected override void WriteTransaction(JsonTextWriter writer, Transaction tx)
WritePropertyValue(writer, "hex", Encoders.Hex.EncodeData(txout.ScriptPubKey.ToRawScript()));

var destinations = txout.ScriptPubKey.GetDestinations().ToArray();


if(destinations.Length == 1)
{
WritePropertyValue(writer, "reqSigs", 1);
WritePropertyValue(writer, "type", GetScriptType(txout.ScriptPubKey.FindTemplate()));
writer.WritePropertyName("addresses");
writer.WriteStartArray();
writer.WriteValue(new BitcoinAddress(destinations[0], Network).ToString());
writer.WriteValue(BitcoinAddress.Create(destinations[0], Network).ToString());
writer.WriteEndArray();
}
else
Expand All @@ -128,7 +128,7 @@ protected override void WriteTransaction(JsonTextWriter writer, Transaction tx)
writer.WriteStartArray();
foreach(var key in multi.PubKeys)
{
writer.WriteValue(new BitcoinAddress(key.ID, Network).ToString());
writer.WriteValue(BitcoinAddress.Create(key.ID, Network).ToString());
}
writer.WriteEndArray();
}
Expand Down
144 changes: 113 additions & 31 deletions NBitcoin/Script.cs
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ public ScriptId ID
}
}

public BitcoinScriptAddress GetAddress(Network network)
public BitcoinScriptAddress GetScriptAddress(Network network)
{
return new BitcoinScriptAddress(ID, network);
}
Expand Down Expand Up @@ -561,64 +561,126 @@ public uint GetSigOpCount(Script scriptSig)
return new Script(scriptSig.ToOps().Last().PushData).GetSigOpCount(true);
}

public PubKey GetSourcePubKey()
public ScriptTemplate FindTemplate()
{
return StandardScripts.GetTemplateFromScriptPubKey(this);
}
static readonly PayToScriptHashTemplate _PayToScriptHash = new PayToScriptHashTemplate();
static readonly PayToPubkeyHashTemplate _PayToPubkeyHash = new PayToPubkeyHashTemplate();

/// <summary>
/// Extract P2SH or P2PH address from scriptSig
/// </summary>
/// <param name="network"></param>
/// <returns></returns>
public BitcoinAddress GetSignerAddress(Network network)
{
var template = new PayToPubkeyHashTemplate();
var result = template.ExtractScriptSigParameters(this);
return result == null ? null : result.PublicKey;
var sig = GetSigner();
if(sig == null)
return null;
return BitcoinAddress.Create(sig, network);
}

public KeyId GetDestination()
/// <summary>
/// Extract P2SH or P2PH id from scriptSig
/// </summary>
/// <returns></returns>
public TxDestination GetSigner()
{
var template = FindTemplate();
var payToPubKeyHash = template as PayToPubkeyHashTemplate;
if(payToPubKeyHash != null)
var pubKey = _PayToPubkeyHash.ExtractScriptSigParameters(this);
if(pubKey != null)
{
return payToPubKeyHash.ExtractScriptPubKeyParameters(this);
return pubKey.PublicKey.ID;
}
var payToPubKey = template as PayToPubkeyTemplate;
if(payToPubKey != null)
var p2sh = _PayToScriptHash.ExtractScriptSigParameters(this);
if(p2sh != null)
{
var result = new PayToPubkeyHashTemplate().ExtractScriptPubKeyParameters(this);
if(result == null)
{
var pub = new PayToPubkeyTemplate().ExtractScriptPubKeyParameters(this);
if(pub != null)
return pub.ID;
}
return p2sh.RedeemScript.ID;
}
return null;
}

public ScriptTemplate FindTemplate()
{
return StandardScripts.GetTemplateFromScriptPubKey(this);
/// <summary>
/// Extract P2SH or P2PH address from scriptPubKey
/// </summary>
/// <param name="network"></param>
/// <returns></returns>
public BitcoinAddress GetDestinationAddress(Network network)
{
var dest = GetDestination();
if(dest == null)
return null;
return BitcoinAddress.Create(dest, network);
}

/// <summary>
/// Extract P2SH or P2PH id from scriptPubKey
/// </summary>
/// <param name="network"></param>
/// <returns></returns>
public TxDestination GetDestination()
{
var pubKeyHashParams = _PayToPubkeyHash.ExtractScriptPubKeyParameters(this);
if(pubKeyHashParams != null)
return pubKeyHashParams;
var scriptHashParams = _PayToScriptHash.ExtractScriptPubKeyParameters(this);
if(scriptHashParams != null)
return scriptHashParams;
return null;
}

public IEnumerable<KeyId> GetDestinations()
/// <summary>
/// Extract P2SH, P2PH address or multiple P2PHs addresses if this script is a multi sig from scriptPubKey
/// </summary>
/// <param name="network"></param>
/// <returns></returns>
public BitcoinAddress[] GetDestinationAddresses(Network network)
{
return GetDestinations()
.Select(id => BitcoinAddress.Create(id, network))
.ToArray();
}
/// <summary>
/// Extract P2SH, P2PH id or multiple P2PHs ids if this script is a multi sig scriptPubKey
/// </summary>
/// <param name="network"></param>
/// <returns></returns>
public TxDestination[] GetDestinations()
{
List<TxDestination> result = new List<TxDestination>();
var single = GetDestination();
if(single != null)
{
yield return single;
result.Add(single);
}
else
{
var result = new PayToMultiSigTemplate().ExtractScriptPubKeyParameters(this);
if(result != null)
var multiSig = new PayToMultiSigTemplate().ExtractScriptPubKeyParameters(this);
if(multiSig != null)
{
foreach(var key in result.PubKeys)
foreach(var key in multiSig.PubKeys)
{
yield return key.ID;
result.Add(key.ID);
}
}
}
return result.ToArray();
}

/// <summary>
/// Get script byte array
/// </summary>
/// <returns></returns>
public byte[] ToRawScript()
{
return _Script.ToArray();
return ToRawScript(false);
}

/// <summary>
/// Get script byte array
/// </summary>
/// <param name="unsafe">if false, returns a copy of the internal byte array</param>
/// <returns></returns>
public byte[] ToRawScript(bool @unsafe)
{
if(@unsafe)
Expand Down Expand Up @@ -654,9 +716,29 @@ public bool Same(Script script)
return Utils.ArrayEqual(script._Script, _Script);
}

public static Script FromBitcoinAddress(BitcoinAddress address)
/// <summary>
/// Create scriptPubKey from destination id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static Script CreateFromDestination(TxDestination id)
{
if(id is ScriptId)
return new PayToScriptHashTemplate().GenerateScriptPubKey((ScriptId)id);
else if(id is KeyId)
return new PayToPubkeyHashTemplate().GenerateScriptPubKey((KeyId)id);
else
throw new NotSupportedException();
}

/// <summary>
/// Create scriptPubKey from destination address
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public static Script CreateFromDestinationAddress(BitcoinAddress address)
{
return new PayToPubkeyHashTemplate().GenerateScriptPubKey(address);
return CreateFromDestination(address.ID);
}
}
}

0 comments on commit 6b2e88c

Please sign in to comment.